zping.com

SQL SERVER,ORACLE数据库分析,设计,研究,优化,重构等

统计

常用链接

留言簿(3)

友情衔接

阅读排行榜

评论排行榜

SQL 语句优化--OR 语句优化案例

     从上海来到温州,看了前几天监控的sql语句和数据变化,发现有一条语句的io次数很大,达到了150万次IO,而两个表的数据也就不到20万,为何有如此多的IO次数,下面是执行语句: 

select ws.nodeid,wi.laststepid,wi.curstepid from Workflowinfo wi, 
Workflowstep ws 
where ws.workflowid='402881db1b441e6f011c0cff320e4766' and (wi.laststepid = ws.id or (wi.curstepid = ws.id and isreceived=1 and issubmited =1)) 

  执行IO统计结果如下:

(22 行受影响)
表 
'workflowstep'。扫描计数 1,逻辑读取 23 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 
'Worktable'。扫描计数 4,逻辑读取 1490572 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 
'workflowinfo'。扫描计数 4,逻辑读取 12208 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 
'Worktable'。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

  执行计划如下:

  

    这里发现:主要是嵌套循环算法占的开销最大。个人感觉是“Or”引起的性能问题,后来根据业务逻辑改写。如下:

    语句修改如下:

  select ws.nodeid,wi.laststepid,wi.curstepid from Workflowinfo wi, Workflowstep ws
where ws.workflowid='402881db1b441e6f011c0cff320e4766' and (wi.laststepid = ws.id) 
union all 
  
select ws.nodeid,wi.laststepid,wi.curstepid from Workflowinfo wi, Workflowstep ws where ws.workflowid='402881db1b441e6f011c0cff320e4766' and  (wi.curstepid = ws.id and isreceived=1 and issubmited =1)

 

   查询IO次数如下:

(22 行受影响)
表 
'workflowinfo'。扫描计数 36,逻辑读取 142 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 
'workflowstep'。扫描计数 2,逻辑读取 46 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

  执行计划如下:

 

   这里发现:成本不在是嵌套循环上的开销了,IO次数大大减少。

   总结:

      这里通过改写”OR“语句成“Union”语句,性能大大提高,用了or语句,数据库优化器无法优化,这里都是用的“嵌套循环算法”,但是使用方式不一样,同样得到不同的结果。

      对于类似的语句,可以将其改写成”Union“ 或”Union All“ 语句。

http://www.zping.com/  热爱祖国

posted on 2008-09-23 16:53 zping.com 阅读(2422) 评论(25)  编辑 收藏 网摘 所属分类: SQL 技巧和优化

评论

#1楼  2008-09-23 17:59 子逸      

好复杂, 慢慢看...   回复  引用  查看    

#2楼  2008-09-23 18:14 斌圣      

如何用来分页呢?
能解决分页问题吗?   回复  引用  查看    

#3楼  2008-09-23 18:54 金色海洋(jyk)      

看着眼熟呀。   回复  引用  查看    

#4楼  2008-09-23 21:46 代码乱了      

好文!SQL性能调优的文章少啊,呵呵
"Union“ 或”Union All“ 还是有区别的吧
  回复  引用  查看    

#5楼  2008-09-23 22:38 深蓝      

恩,这样优化比较好。   回复  引用  查看    

#6楼  2008-09-23 23:33 AK47      

好文章,楼主多发些关于SQL性能优化的文章   回复  引用  查看    

#7楼  2008-09-24 08:44 aierong      

good

  回复  引用  查看    

#8楼  2008-09-24 09:09 足够有晋      

学习了,哪是否使用or的地方都可以这样调整哪?
那or是否就没有使用的意义了哪?   回复  引用  查看    

#9楼  2008-09-24 09:12 testsql [未注册用户]

想问一下,楼主的SQL性能图是用什么工具可以查看到的?   回复  引用    

#10楼  2008-09-24 09:39 zyli      

楼主为什么我这样写
SELECT ID, V.UNIT_CODE, YEAR, VOU_NO, VOU_DATE, VOU_TYPE, SUBJECTID, RMB_DEBIT, RMB_CREDIT,LEFT(SUBJECTID,@GRADE_LEN),1,SUMMARY,CURRD,CURRC,AMOUNTD,AMOUNTC,V.BLANCE
FROM #VOUCHER_DETAIL V,#BLANCE B WHERE V.UNIT_CODE=B.UNIT_CODE AND V.VOU_DATE>=@BEGIN_DATE AND VOU_DATE<=@END_DATE AND STATUS=0 AND
@NUM4=4 AND PARENTSUBJECTID=@SUBJECTID4 AND CURRD>@MONEY4*B.BLANCE/100
union
SELECT ID, V.UNIT_CODE, YEAR, VOU_NO, VOU_DATE, VOU_TYPE, SUBJECTID, RMB_DEBIT, RMB_CREDIT,LEFT(SUBJECTID,@GRADE_LEN),1,SUMMARY,CURRD,CURRC,AMOUNTD,AMOUNTC,V.BLANCE
FROM #VOUCHER_DETAIL V,#BLANCE B WHERE V.UNIT_CODE=B.UNIT_CODE AND V.VOU_DATE>=@BEGIN_DATE AND VOU_DATE<=@END_DATE AND STATUS=0 AND
@NUM4=4 AND PARENTSUBJECTID=@SUBJECTID4 AND CURRC>@MONEY4*B.BLANCE/100

比这样写

SELECT ID, V.UNIT_CODE, YEAR, VOU_NO, VOU_DATE, VOU_TYPE, SUBJECTID, RMB_DEBIT, RMB_CREDIT,LEFT(SUBJECTID,@GRADE_LEN),1,SUMMARY,CURRD,CURRC,AMOUNTD,AMOUNTC,V.BLANCE
FROM #VOUCHER_DETAIL V,#BLANCE B WHERE V.UNIT_CODE=B.UNIT_CODE AND V.VOU_DATE>=@BEGIN_DATE AND VOU_DATE<=@END_DATE AND STATUS=0 AND
@NUM4=4 AND PARENTSUBJECTID=@SUBJECTID4 AND ( CURRD>@MONEY4*B.BLANCE/100 or CURRC>@MONEY4*B.BLANCE/100 )

要慢很多阿
  回复  引用  查看    

#11楼 [楼主] 2008-09-24 09:55 zping.com      

@足够有晋
不能全部采用这样的方式,没有特定的范式。   回复  引用  查看    

#12楼 [楼主] 2008-09-24 10:04 zping.com      

@zyli
你把这些语句的“执行计划图”发上来,这些语句看不明白!   回复  引用  查看    

#13楼  2008-09-24 10:10 姜敏      

真不错,慢慢学习.   回复  引用  查看    

#14楼  2008-09-24 10:11 过江      

请问
表 'workflowinfo'。扫描计数 36,逻辑读取 142 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'workflowstep'。扫描计数 2,逻辑读取 46 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。是怎么弄出来的呀??   回复  引用  查看    

#15楼 [楼主] 2008-09-24 10:30 zping.com      

@过江
打开sql server查询分析器的IO统计。命令如下:set statistics io on   回复  引用  查看    

#16楼  2008-09-24 10:31 BAsil      

不错,顶一个   回复  引用  查看    

#17楼  2008-09-24 10:53 gzj [未注册用户]

请问在哪里 监控 服务器上执行的sql语句和数据变化历史?   回复  引用    

#18楼 [楼主] 2008-09-24 11:00 zping.com      

@gzj
自己写语句,再通过job每天调度,将数据保存到表里。   回复  引用  查看    

#19楼  2008-09-24 14:25 James-yu      

我想问题是两个表做了连接,但是SQL SERVER没有分析出链接语句,楼主麻烦测试一下

select ws.nodeid,wi.laststepid,wi.curstepid from
Workflowstep ws left join Workflowinfo wi on (wi.laststepid = ws.id or (wi.curstepid = ws.id and isreceived=1 and issubmited =1)) where ws.workflowid='402881db1b441e6f011c0cff320e4766'   回复  引用  查看    

#20楼 [楼主] 2008-09-24 16:14 zping.com      

@James-yu
测试过了,能分析出语句,但是执行计划不是最优,造成速度奇慢。   回复  引用  查看    

#21楼  2008-09-24 17:46 James-yu      

表 'Worktable'。扫描计数 4,逻辑读取 1490572 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
--------------

Worktable 是那个表,SQL语句里面没有,isreceived=1 and issubmited =1 是那个表里面的field ,能否大致说明一下每个表的数据量(行数)和相关的结构(不影响理解SQL语句就行)?   回复  引用  查看    

#22楼 [楼主] 2008-09-24 19:50 zping.com      

@James-yu
刚刚重新查了一下,正确的数据:Workflowinfo约有13万, Workflowstep约 14万。
(isreceived,issubmited)为表Workflowinfo 的字段
Worktable 是数据库查询的自动的临时表。   回复  引用  查看    

#23楼  2008-09-24 23:46 RicCC      

前面的语句,2个表需要join,join条件为or的关系,sql server对workflowinfo做了23次全表扫描进行join匹配
后面的语句人为把join拆解到union的2个子句中,每次join都可以利用索引,并且索引的选择性比较好

sql server的优化不是找最优解,只是找出一个可行、较优的方案,如果语句中多几个这样的or条件,拆解组合的方案将成指数级增长,查询编译的开销太大   回复  引用  查看    

#24楼 [楼主] 2008-10-04 15:39 zping.com      

@zyli
能给出表机构和一些数据分布吗,这样看不懂啊!   回复  引用  查看    

#25楼  2008-10-07 10:06 Eric Luo      

union和union all还是有区别的,前者要排序   回复  引用  查看    


标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2008-09-26 16:39 编辑过
Google站内搜索


相关链接: