一个 提高SQL 查询的讨论帖

idn(关键字),产品名称,产品数量...
B表,有字段:idn,a_idn(记录A表的关键字),工序,工时...
A表与B表是一对多的关系,
我想取到A表的明细及B表相关的总工时
sele aa.* from a aa left outer join 
  (select a_idn,sum(工时) from b group by a_idn) bb on aa.idn=bb.a_idn
这样虽然取得到我要的结果,可是速度很慢,尤其是我还有其它的表需要这样连接,一层套一层,导致速度奇慢无比,二千多条数据,要七八分钟才得到结果.这样肯定不行.
请问应该怎么写才能提高查询速度?急盼高手提点


不应该啊,我觉得1s内就应该搞定,就这么一个查询,没有别的么。
还有你说的两千多条是之A表,还是B表?


语句并不复杂,不应该市语句的问题


A表加了条件才二千多条数据,今天客户打电话来说,查询时提示超时链接,我用SQL调试发现
就是这个问题,左链接套了六层,一层比一层慢,最后就超时了!


当然套一层左链接,慢是慢点,但还能出来,但是套多了就会链接超时!!!有没有改善办法?
实在没法子只好用循环了,惨~~~~~~


你用视图试试


你的业务逻辑很复杂么,应该不至于7,8分钟的,不行的话,你就建临时表吧,把中间结果放进去。


......如果只是单纯的表与表链接速度很快,可是与GROUP by的统计结果再左链接速度就明显慢,我试试把统计做成用视图后再链接会不会快


我的表不复杂,就是主表的[客户,加工类型,项目名称]都记的是代码,要中文信息,得在另三个对照表里取,还有要两个统计结果:到货数和加工工时,分别汇算自另外两个表.
所以左链接套了六层...


视图是不会提高效率的,它只是为了控制权限,或是查询格式。


不要使用LEFT OUTER JOIN
效率很低
你这样写吧
sele aa.* from a aa,  
  (select a_idn,sum(工时) from b group by a_idn) bb where aa.idn=bb.a_idn


sele aa.* from a aa,  
  (select a_idn,sum(工时) from b group by a_idn) bb where aa.idn=bb.a_idn
这样写有一个问题,不能把A表全部的数据显示出来呀


能不能用存储过程呢?


有这么夸张吗?感觉SQL语句不复杂,我更复杂的都写过,都用上游标了也没有这么慢啊。要不LZ用临时表试一下,临时表记录B表的总工时,这样可能会好一点把


这种情况有一个通用的解决办法:根据情况你建立一个或者多个临时表,因为每个临时表数据量都不多,所以不会出现数据库链接超时的情况,万一数据量比较大,执行时间比较久,你还可以用进度条标识进度.


可以这样
select a.产品名称,a.产品数量 sum(b.工时)
from A表 a,B表 b
where a.idn = b.a_idn
group by a.产品名称,a.产品数量


是不复杂,可能是左链接套得太多,尤其和GROUP by的子查询进行左链接,会影响查询速度.
临时表我一直没敢用,
SELECT * INTO #tmp FROM 表,
如果网络个多个用户同时查询,执得这条语句会不会冲突啊?临时表会自动删掉吧?


不会冲突的,会话结束就删除了。


临时表是微软都建议尽量避免使用,用了肯定慢
优化一下索引试试
用查询分析器的执行计划看看慢在哪儿


我试过了,普通表左链速度很快,就是和GROUP by的子查询进行左链接,会影响查询速度,
看来没有什么好办法了,我还是做循环得了~~~~~


sele aa.*,b.a_idn,b.sum(工时) from a aa left join b group by a_idn on  aa.idn=bb.a_idn


循环会快?group by 是会慢要按索引扫描表然后求和;b表的记录数有多少


b表35824条数据,group by 后35677条,.........

sele aa.*,b.a_idn,b.sum(工时) from a aa left join b group by a_idn on  aa.idn=bb.a_idn
我试试,再问一下left join 和left outer join是不是一样的


sele aa.*,b.a_idn,b.sum(工时) from a aa left join b group by a_idn on  aa.idn=bb.a_idn
按这个格式试过一次了,提示"在关键字 'group' 附近有语法错误。",不行啊


楼主是不是只有b表的数据3w条,那么你可以试试先让a与b的关联的结果插入到临时表,再用临时表进行下面的4个关联,那样应该可以快一些。


如果在select里用子查询呢?比如:
sele aa.*,(select sum(工时) from b where aa.idn=b.a_idn) as 工时
from a aa 
(可能更慢!)
凡是有子查询的,一般都慢!


A表37316条记录,取多少数据,视条件而定,或多或少不一定的.
与B表类同的还有C表,有近6万条数据....
本来一个SQL语句就能搞定的,现在弄得烦死人了!


如果是sqlserver2000
那么可以用
declare @temp table(a varchar(10),b int)
insert into @temp select a,b from ab where a='a'
这样的临时表优化嵌套查询


如果在select里用子查询呢?比如:
sele aa.*,(select sum(工时) from b where aa.idn=b.a_idn) as 工时
from a aa 
(可能更慢!)
凡是有子查询的,一般都慢!
--------------------------
我试了一下,3万条数据蛮快的,而且一条不少,真是非常感谢你!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


谢谢各位的帮忙!非常感谢!yeskert1的答案解决了我大问题,不然要重写代码了!


那楼主把你原来嵌套的group by 都去掉呢,你那样的写法&子查询应该没有差别啊,无非是少了个group by。


A表3万条,B表3万条,单纯的left outer join速度很快,就是用group by 速度明显下降,

yeskert1的答案,我试的时候蛮快的,怎么结完贴回去再试,就慢下来了呢,不过比原来的超时,总算是快点了,至少不会超时了.


哈,我发现一个奇怪的现象,用yeskert1的办法,加条件反而比不加条件时慢,

按理说加了条件,才二千条数据,应该更快才对,真是奇怪


用SQL查询分析器,不加条件,14秒就涮出结果了,加了条件,1分半钟已过,结果还没出来.
泪奔~~~~~~~~~~~~~~~~~~~`


你把完整语句贴出来看看


>>加条件反而比不加条件时慢,
这是可能的,因为条件必然有比对的过程,字符串比较是耗时间的。group by a_idn导致慢也是这个原因。
一般,这时应该为表增加索引来改善速度。

能把完整语句贴出来吗?


SELECT *
FROM (SELECT c.*, isnull(d .wcsl, 0) AS wcsl
        FROM (SELECT a.*, isnull(a.sl * b.zgs, 0) AS zgs
                FROM (SELECT a.*, isnull(b.xzlx, ' ') AS xzlx_sm
                        FROM (SELECT c.*, isnull(d .qym, ' ') AS qym
                                FROM (SELECT a.*, isnull(b.xmm, ' ') AS xmm
                                        FROM ww_wwjl a LEFT OUTER JOIN
                                              xmk b ON a.xm_dir = b.dir) c LEFT OUTER JOIN
                                      ww_khdak d ON c.khdm = d .khdm) a LEFT OUTER JOIN
                              ww_xzlx b ON a.xzlx = b.xzlx_path) a LEFT OUTER JOIN
                          (SELECT wwjl_idn, SUM(gs) AS zgs
                         FROM ww_wwjl_gs
                         WHERE (sbname <> '@#$%')
                         GROUP BY wwjl_idn) b ON a.idn = b.wwjl_idn) c LEFT OUTER JOIN
                  (SELECT wwjl_idn, SUM(dhsl) AS wcsl
                 FROM ww_wwdh
                 WHERE dhrq >= '2006-01-01' AND dhrq <= '2006-12-31'
                 GROUP BY wwjl_idn) d ON c.idn = d .wwjl_idn) DERIVEDTBL
WHERE (cj = '机械四课') AND (wwrq >= '2006-01-01') AND (wwrq <= '2006-12-31')
ORDER BY xm_dir, th


------------------
一共六个表:
ww_wwjl是主表,与以下五个表左连接
|---->xmk  (ww_wwjl.xm_dir=xmk.dir)
|---->ww_khdak (ww_wwjl.khdm=xmk.khdm)
|---->ww_xzlx (ww_wwjl.xzlx=xmk.xzlx_path)
|---->ww_wwjl_gs (SUM(gs) group by wwjl_idn | ww_wwjl.idn=ww_wwjl_gs.wwjl_idn )
|---->ww_wwdh  (SUM(dhsl) group by wwjl_idn | ww_wwjl.idn=ww_wwjl_gs.wwjl_idn )

不知道有没有讲清楚~~~~


头大了!太复杂了![:(]


-_-|||,不管了,循环循环


select a.*,b.... 
from ww_wwjl a left join xmk b on a.xm_dir = b.dir
               left join ww_khdak c on a.khdm = c.khdm
               left join ww_xzlx d on a.xzlx = d.xzlx_path
               left join (SELECT wwjl_idn, SUM(gs) AS zgs 
                          FROM ww_wwjl_gs WHERE (sbname <> '@#$%') 
                          GROUP BY wwjl_idn) e ON a.idn = e.wwjl_idn
       left join (SELECT wwjl_idn, SUM(dhsl) AS wcsl
                          FROM ww_wwdh
                          WHERE dhrq >= '2006-01-01' AND dhrq <= '2006-12-31'
                          GROUP BY wwjl_idn) f ON a.idn = f.wwjl_idn
WHERE (cj = '机械四课') AND (wwrq >= '2006-01-01') AND (wwrq <= '2006-12-31')
ORDER BY xm_dir, th


doud2006谢谢,不过如果符合条件的记录数多的话,还是很慢很慢


你的关联字段都是索引字段吗,不用的字段尽量不写,少出现*;结果对吗,没有重复关联吧


不是啊,我没有用索引,我没有用过索引,只有ww_wwjl的idn是关键字
记录数是对的,没有重复的关联


没索引是全表扫描,当然慢,6个表关联字段都加索引试试;如果这几个表不是很频繁更新不包括insert; where 条件也尽可能用索引;


请问,加了索引,会不会影响我其它的查询语句呀??????


呀,下班了,我明天来试.谢谢


索引会提高查询效率,在数据发生变化时需要更新索引,会降低更新效率


我对索引不是很明白,在网上找了资料看看了,还有很多不懂的地方.
请问unique values打上勾是不是就是群集索引了?

在非群集索引下,数据在物理上随机存放在数据页上,在范围查找时,必须执行一次表扫描才能找到这一范围内的全部行。

在群集索引下,数据在物理上按顺序在数据页上,重复值也排列在一起,因而在范围查找时,可以先找到这个范围的起末点,且只在这个范围内扫描数据页,避免了大范围扫描,提高了查询速度。

那么非群集索引与没用索引不是没区别了吗?象我要汇算总工时,group by,就需要用群集索引了是不是?


你可以查一下sqlserver2000的帮助CREATE INDEX;解释的很清楚了


我试过了,我对需要GROUP  by 的字段进行了聚集索引,速度快了好多哦!不知道会不会对其它操作有影响!我还要测试一下.不过,我先得向你道谢.可是我已经结贴了,不知道还有没有其它办法给你加分呀doud2006


不过我有一个问题,我现在只有一个字段group by ,如果我还有别的字段也需要GROUP by的话,但聚集索引只能做一次,那么是不是只能将建立索引放在程序里啊?这样频繁得删除建立聚集索引可取吗?

posted on 2008-10-16 22:38  cy163  阅读(1295)  评论(0编辑  收藏  举报

导航