zping.com

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

统计

常用链接

留言簿(3)

友情衔接

阅读排行榜

评论排行榜

SQL优化--使用 EXISTS 代替 IN 和 inner join来选择正确的执行计划

    在使用Exists时,如果能正确使用,有时会提高查询速度:

      1,使用Exists代替inner join

      2,使用Exists代替 in

 

  1,使用Exists代替inner join例子:

     在一般写sql语句时通常会遇到如下语句:

      两个表连接时,取一个表的数据,一般的写法通过关联查询(inner join):      

select a.id, a.workflowid,a.operator,a.stepid
from  dbo.[[zping.com]]] a
inner join workflowbase b on a.workflowid=b.id
and operator='4028814111ad9dc10111afc134f10041'

 

查询结果:

(1327 行受影响)
表 
'Worktable'。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 
'workflowbase'。扫描计数 1,逻辑读取 293 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 
'[zping.com]'。扫描计数 1,逻辑读取 1339 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

 

   还有一种写法使用exists来取数据

select a.id,a.workflowid,a.operator ,a.stepid
from  dbo.[[zping.com]]] a where exists
(
select 'X' from workflowbase b where a.workflowid=b.id)
and operator='4028814111ad9dc10111afc134f10041'

 执行结果:  

(1327 行受影响)
表 
'[zping.com]'。扫描计数 1,逻辑读取 1339 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 
'workflowbase'。扫描计数 1,逻辑读取 291 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

 

   这里两着的IO次数,EXISTS比inner join少 2个IO, 对比执行计划成本不一样, 看看两着的差异:  

 

 

   这时我们发现使用EXISTS要比inner join效率稍微高一下。  
     2,使用Exists代替 in

      要求:编写workflowbase表中id不在表中dbo.[[zping.com]]]的行:      

       一般的写法:

select * from workflowbase 
 
where  id not in (
select  a.workflowid
from  dbo.[[zping.com]]] a )

执行结果:


(
1 行受影响)
表 
'Worktable'。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 
'[zping.com]'。扫描计数 5,逻辑读取 56952 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 
'workflowbase'。扫描计数 3,逻辑读取 1589 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 
'Worktable'。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

    使用Existsl来写:

select * from workflowbase b
 
where not exists(
select 'X'
from  dbo.[[zping.com]]] a where a.workflowid=b.id )

   看看执行结果

(1 行受影响)
表 
'Worktable'。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 
'[zping.com]'。扫描计数 3,逻辑读取 18984 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 
'workflowbase'。扫描计数 3,逻辑读取 1589 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

  两个io的差距:56952+1589=58541次 (使用IN)

                     18984+1589=20573次  (使用Exists)

   使用exists是in的2.8倍,查询性能提高很大。

 

 

   EXISTS 使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果。

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

posted on 2008-08-05 20:52 zping.com 阅读(2556) 评论(32)  编辑 收藏 网摘 所属分类: SQL 技巧和优化

评论

#1楼  2008-08-05 22:33 PerfectDesign      

麻烦楼主sp_help一下两表,优化的时候最好能看到索引的情况   回复  引用  查看    

#2楼  2008-08-05 22:39 PerfectDesign      

你仔细看你的统计信息,扫描居然有三次之多!很显然不是缺乏适当的索引。
初步看起来workflowid这个字段上可选性很低,而且你建了索引的。
你的俄RID查找占了那么多开销   回复  引用  查看    

#3楼  2008-08-05 22:58 荔橙伊珊雨      

?   回复  引用  查看    

#4楼  2008-08-05 23:34 读后感 [未注册用户]

还没看完就知道博主会被喷……果然不出所料。博主要加油啊!   回复  引用    

#5楼  2008-08-05 23:45 i.Posei      

@读后感
呵呵,但我看到图片上的网址的时候就有你这样的想法了。   回复  引用  查看    

#6楼  2008-08-05 23:53 Eeyore      

喷一下~,太过片面了...   回复  引用  查看    

#7楼  2008-08-06 00:28 深蓝      

确实片面,不可能通过一两个例子就说明这个比那个好。具体问题具体分析。   回复  引用  查看    

#8楼  2008-08-06 08:40 airwolf2026      

俺公司的DBA前不久专门演示了下oralce基于规则优化和基于代价优化的例子.结果在基于规则优化的情况下,用NOT IN 或者EXISTS等语句是一样的性能的.所以...   回复  引用  查看    

#9楼  2008-08-06 08:57 阿新      

Exists,IN 是无法使用索引的,对大表的操作自然性能会慢.   回复  引用  查看    

#10楼  2008-08-06 09:06 PerfectDesign      

http://www.cnblogs.com/perfectdesign/archive/2008/08/06/sql_exists_in.html

@阿新
exists,in也是可以用索引的   回复  引用  查看    

#11楼  2008-08-06 09:16 Eeyore      

个人经验join>=exists>=in   回复  引用  查看    

#12楼 [楼主] 2008-08-06 09:22 zping.com      

@PerfectDesign
在这里谢谢大家的批评和指正!
Exists和in,在有些情况下是性能是一样的。可以使用Exists代替in,但不能使用in来代替Exists,
还有就是我做的用Exists代替inner join是在没有去取另一个表的数据情况下。是有条件的   回复  引用  查看    

#13楼  2008-08-06 09:29 陛下(Howard - 2341)      

需要有个权威的达人说说啊,否则我们这些数据库操作的懵懂者会很迷茫滴!不过感谢楼主各位的讨论啊!   回复  引用  查看    

#14楼  2008-08-06 09:29 PerfectDesign      

  回复  引用  查看    

#15楼 [楼主] 2008-08-06 09:32 zping.com      

@PerfectDesign
刚刚看了楼上的blog关于三者的对比,
http://www.cnblogs.com/perfectdesign/archive/2008/08/06/sql_exists_in.html
可能是我数据库中两个表的数据分布和你的测试的表数据分布不一样,造成了楼上的3者没有性能区别。
但可以得出使用Exists并不比inner join 和in性能差   回复  引用  查看    

#16楼  2008-08-06 12:23 赫尔梅斯      

楼主用的是什么工具?   回复  引用  查看    

#17楼 [楼主] 2008-08-06 12:50 zping.com      

@赫尔梅斯
就是用SQL server 2005自带的查询分析器啊!   回复  引用  查看    

#18楼  2008-08-06 13:08 zxbyh [未注册用户]

那个说的 Exists 就一定比 in 好??

是有前提的
对于小表,用in要好些。   回复  引用    

#19楼  2008-08-06 16:27 真见      

我觉得in很googd啊。   回复  引用  查看    

#20楼  2008-08-06 17:08 曲滨*銘龘鶽      

Exists 对性能的提升

在许多不同的数据库是有差异的;

Exists 在有些数据库如 sqlserver 在某些查询上就会表现比较快
而在在 Oracle 可能就和 in 差不多
所以证明 sqlserver 对代码预编译优化上还是有些欠缺;

不过有些东西是没法用 in 完成的必须用 Exists   回复  引用  查看    

#21楼  2008-08-06 17:25 爱在戏院前      

哈哈,果然被喷~~我昨天看到这个文章,就已经潜意识感觉会被喷了……   回复  引用  查看    

#22楼  2008-08-06 18:18 hxm      

dbanotes
  回复  引用  查看    

#23楼 [楼主] 2008-08-06 19:14 zping.com      

@i.Posei
将文章中的网址屏蔽了,以免误会。
  回复  引用  查看    

#24楼  2008-08-13 17:28 aierong      

没有绝对谁比谁快

有时3者是一样的,因为查询优化器的作用   回复  引用  查看    

#25楼  2008-08-22 08:32 hi [未注册用户]

一般会用left join 替代   回复  引用    

#26楼 [楼主] 2008-08-22 09:22 zping.com      

用left join速度会更慢的。   回复  引用  查看    

#27楼  2008-08-22 10:27 PerfectDesign      

@zping.com
left 和inner只要查询结果一样,效率是一模一样的,没有什么left更慢的说法,只有需求不同   回复  引用  查看    

#28楼 [楼主] 2008-09-05 20:38 zping.com      

@PerfectDesign
不是啊,inner join和left join的处理方式不一样的,inner join性能要优于left join   回复  引用  查看    

#29楼  2008-09-05 21:23 PerfectDesign      

呵呵,你还是再看看吧   回复  引用  查看    

#30楼 [楼主] 2008-09-06 21:20 zping.com      

@PerfectDesign
这个问题,不是我说的啊,而是专家这样说的“inner join性能要优于left join ”   回复  引用  查看    

#31楼  2008-09-07 08:46 PerfectDesign      

内连接和做链接的本质是先产生笛卡尔积,然后匹配连接符,这一步骤就满足了内连接,然后如果有落单的null,则在第三步满足左连接
如果在2表连接结果都一样的情况下,第三步是不会被执行的,也就是说内连接和左联接的执行计划是一样的。
左连接和内联接两者性能好不好的比较我觉得没有任何意义,因为两者都是满足不同的需求,相比较的一个最基本的,就是测试环境一样,需求一样,如果这两个都满足不了,怎么能说他们两者比较有何意义呢?
就好像残奥会和奥运会,非要搁在一起比较,一定要能强求人家非要跟博尔特似的吗?   回复  引用  查看    

#32楼  2008-09-25 21:13 啊合 [未注册用户]


加油,加油,这个方面的东东好多啊。
说来说去,SQL2005不会那么笨吧,给个IN,然后给个exists ,然后说exists 比IN 好啊好……
倒下了   回复  引用    


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


相关链接: