飘易博客(作者:Flymorn)
订阅《飘易博客》RSS,第一时间查看最新文章!
飘易首页 | 留言本 | 关于我 | 订阅Feed

WHERE条件中or与union引起的全表扫描的问题

Author:Flymorn Source:飘易博客
Categories:数据库 PostTime:2008-10-8 22:14:45
正 文:
    说起数据库的SQL语句执行效率的问题,就不得不提where条件语句中的or(逻辑或)引起的全表扫描问题,从而导致效率下降。

    在以往绝大多数的资料中,大多数人的建议是使用 union 代替 or ,以解决由于使用了 OR 导致的全表扫描。然而,实际是不是如此呢?flymorn就拿5万多条数据的MSSQL数据库来测试。

    在SQL Server查询分析器中键入如下代码:

SET STATISTICS profile ON
SET STATISTICS io ON
SET STATISTICS time ON 
go
select * from chuzu where c_id>1000 or c_qu='沙坪坝区' order by c_time desc

select * from chuzu where c_id>1000 
union
select * from chuzu where c_qu='沙坪坝区' order by c_time desc
go
SET STATISTICS profile OFF
SET STATISTICS io OFF
SET STATISTICS time OFF

    数据库设计中,id为主键,同时也是聚集索引,qu是普通字段列,两个条件中的字段是不一样的。

    执行计划如下:
WHERE条件中or与union引起的全表扫描的问题

    从执行计划中可以看出,采用了 union 的SQL语句的查询成本为50.22%,比采用 or 的成本 49.78%稍多,当然这只是计划。我们再来看看执行效率:

(所影响的行数为 52713 行)
表 'chuzu'。扫描计数 1,逻辑读 2412 次,物理读 0 次,预读 0 次。
SQL Server 执行时间: CPU 时间 = 938 毫秒,耗费时间 = 3222 毫秒。

(所影响的行数为 52713 行)
表 'chuzu'。扫描计数 2,逻辑读 4774 次,物理读 0 次,预读 0 次。
SQL Server 执行时间:  CPU 时间 = 1484 毫秒,耗费时间 = 4323 毫秒。

    从这样的数据可以看出,采用了 union 的SQL语句的效率(4323 毫秒)实际上并没有比采用 or (3222 毫秒) 的高,耗费的时间也要多,采用了 or 的效率反而高出了25%。

    如果where条件中的是同一个字段的话,执行效率也大体如上。

SET STATISTICS profile ON
SET STATISTICS io ON
SET STATISTICS time ON 
go
select * from chuzu where c_qu='九龙坡区' or c_qu='沙坪坝区' order by c_time desc

select * from chuzu where c_qu='九龙坡区'
union
select * from chuzu where c_qu='沙坪坝区' order by c_time desc
go
SET STATISTICS profile OFF
SET STATISTICS io OFF
SET STATISTICS time OFF

   在这样的执行计划中,union 成本为 60.75% ,采用 or 的成本为 39.25%。依然是or的效率高。
WHERE条件中or与union引起的全表扫描的问题

   再来看执行结果:

(所影响的行数为 6131 行)
表 'chuzu'。扫描计数 1,逻辑读 2412 次,物理读 0 次,预读 0 次。
SQL Server 执行时间:  CPU 时间 = 203 毫秒,耗费时间 = 635 毫秒。

(所影响的行数为 6131 行)
表 'chuzu'。扫描计数 2,逻辑读 4824 次,物理读 0 次,预读 0 次。
SQL Server 执行时间:  CPU 时间 = 360 毫秒,耗费时间 = 798 毫秒。

    采用union的执行时间 798 ms ,or的时间是 635ms,效率上来说,依然是 or 的效率高。

    总结:我的测试结果正和网上说的相反,也许是因为我的数据量还不够大,才5万多的数据;或许当数据量到了百万千万级的时候,union 的效率 就会比 or 的高了。

     所以,我的理解是在数据量还没有足够大,sql语句中还是尽量用 or 条件查询,因为数据量不大的情况下,即使全表扫描也要比逻辑读两次,扫描两次的时间要少,效率要高;当然,如果你的数据达到百万级别以上了,那就不要用 or 了,可以用 union 或 union all 代替 or ,以避免因为 or 引起的全表扫描。
作者:Flymorn
来源:飘易博客
版权所有。转载时必须以链接形式注明作者和原始出处及本声明。
上一篇:ASP的高效率的分页算法
下一篇:SQL语句执行效率及性能测试
1条评论 “WHERE条件中or与union引起的全表扫描的问题”
1 Enric Xiao
2012-4-14 4:11:30
作者的想法是正确的,我用37万数据测试,结果OR用了51s,而union只用了30s,呵呵
发表评论
名称(*必填)
邮件(选填)
网站(选填)

记住我,下次回复时不用重新输入个人信息
© 2007-2010 飘易博客 Www.Piaoyi.Org 原创文章版权由飘易所有 渝ICP备07006361号