欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  数据库

SQL in与exists的执行效率比较

程序员文章站 2022-04-14 17:44:10
...

SQL中in可以分为三类: 形如select * from t1 where f1 in ('a','b'),应该和以下两种比较效率:select * from t1 where f1='a' or f1='b' 或者 select * from t1 where f1 ='a' union all select * from t1 f1='b',你可能指的不是这一类,这里不做讨论。

SQL中in可以分为三类:

  • 形如select * from t1 where f1 in ('a','b'),应该和以下两种比较效率:select * from t1 where f1='a' or f1='b' 或者 select * from t1 where f1 ='a' union all select * from t1 f1='b',你可能指的不是这一类,这里不做讨论。
  • 形如select * from t1 where f1 in (select f1 from t2 where t2.fx='x'),其中子查询的where里的条件不受外层查询的影响,这类查询一般情况下,自动优化会转成exist语句,也就是效率和exist一样。
  • 形如select * from t1 where f1 in (select f1 from t2 where t2.fx=t1.fx),其中子查询的where里的条件受外层查询的影响,这类查询的效率要看相关条件涉及的字段的索引情况和数据量多少,一般认为效率不如exists。除了第一类in语句都是可以转化成exists 语句的SQL,一般编程习惯应该是用exists而不用in,而很少去考虑in和exists的执行效率。

A,B两个表

  • 当只显示一个表的数据如A,关系条件只一个如ID时,使用IN更快:select * from A where id in (select id from B)
  • 当只显示一个表的数据如A,关系条件不只一个如ID,col1时,使用IN就不方便了,可以使用EXISTS:select * from A where exists (select 1 from B where id = A.id and col1 = A.col1)
  • 当只显示两个表的数据时,使用IN,EXISTS都不合适,要使用连接:select * from A left join B on id = A.id

所以使用何种方式,要根据要求来定。

这是一般情况下做的测试:

set statistics io on 
select * from sysobjects where exists (select 1 from syscolumns where id=syscolumns.id) 
select * from sysobjects where id in (select id from syscolumns ) 
set statistics io off 
(47 行受影响)
表'syscolpars'。扫描计数 1,逻辑读取 3 次,物理读取 0 次,预读 2 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表'sysschobjs'。扫描计数 1,逻辑读取 3 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
(1 行受影响)
(44 行受影响)
表'syscolpars'。扫描计数 47,逻辑读取 97 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表'sysschobjs'。扫描计数 1,逻辑读取 3 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
(1 行受影响)
set statistics io on 
select * from syscolumns where exists (select 1 from sysobjects where id=syscolumns.id) 
select * from syscolumns where id in (select id from sysobjects ) 
set statistics io off 
(419 行受影响)
表'syscolpars'。扫描计数 1,逻辑读取 10 次,物理读取 0 次,预读 15 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表'sysschobjs'。扫描计数 1,逻辑读取 3 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
(1 行受影响)
(419 行受影响)
表'syscolpars'。扫描计数 1,逻辑读取 10 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表'sysschobjs'。扫描计数 1,逻辑读取 3 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
(1 行受影响)

测试结果(总体来讲exists比in的效率高):

效率:条件因素的索引是非常关键的

把syscolumns 作为条件:syscolumns 数据大于sysobjects

用in 扫描计数 47,逻辑读取 97 次,用exists 扫描计数 1,逻辑读取 3 次。把sysobjects作为条件:sysobjects 的数据少于 syscolumns,exists 比 in 多预读 15 次。

如果要查询每个类别的最大sid 的话

select * from test a 
  where not exists(select 1 from test where sort = a.sort and sid > a.sid) 

select * from test a 
  where sid in (select max(sid) from test where sort = a.sort) 

的执行效率要高三倍以上。

sql优化中,使用in和exist? 主要是看你的筛选条件是在主查询上还是在子查询上。