在数据库查询中避免使用OR子句会更好吗?

时间:2014-09-23 14:32:32

标签: android sql sqlite android-sqlite database-performance

假设我有一个数据库设置和一个名为MyTable的表,其中包含大量记录(数万个)。假设查询如下......

select * from MyTable where ColumnX = 'X'

...只返回少量记录(< 10)。我们想要将此结果集进一步过滤为仅ColumnY匹配'Y1''Y2'的记录。从速度和内存的角度来看,简单地修改为上面的查询是否更好......

select * from MyTable where ColumnX = 'X' and (ColumnY = 'Y1' or ColumnY = 'Y2')

...或者是否更好地迭代代码中的(小)结果集并仅筛选出ColumnY匹配'Y1''Y2'的记录?我问的原因是因为我从性能角度(处理大型表时)被告知OR子句在数据库查询中是不好的,并且在可能的情况下更好地避免。

  

注意:这适用于我的场景是一个带有本地SQLite数据库的Android应用程序,但我想这个问题比那个更通用。

3 个答案:

答案 0 :(得分:1)

SQLite的文档描述了可以对带有OR的查询执行的multiple optimizations,并说:

  

对于任何给定的查询,可以使用此处描述的OR子句优化这一事实并不能保证它将被使用。 SQLite使用基于成本的查询计划程序来估计各种竞争查询计划的CPU和磁盘I / O成本,并选择它认为最快的计划。如果WHERE子句中有许多OR术语,或者单个OR子句子项的某些索引不是非常有选择性,那么SQLite可能会认为使用不同的查询算法甚至是全表扫描更快。应用程序开发人员可以在语句上使用EXPLAIN QUERY PLAN前缀来获得所选查询策略的高级概述。

在任何情况下,在代码中手动实现OR很可能比让数据库执行它更慢,因为数据库必须读取并返回ColumnX上匹配的所有行,即使是那些与ColumnY不匹配。

此外,数据库已经有代码来执行此过滤;再次实现它只会增加代码的复杂性和错误的可能性。

OR子句在性能方面(在处理大型表时更好地避免)在数据库查询中是错误的并且在可能的情况下更好地避免”的说法并不完全正确;如果你需要OR,所有选择都会更糟。

答案 1 :(得分:0)

您可以尝试使用IN子句:

select * from MyTable where ColumnX = 'X' and ColumnY in ('Y1','Y2')

答案 2 :(得分:-2)

是的,Ajay你说得对,谢谢。 解决此问题的另一种方法是使用临时表或With子句。

-- Following solution for Oracle , need little change for each db product to replace DUAL

with YT (columnY)( select 'Y1' as columnY from DUAL
         union 
         select 'Y2' from DUAL)
select MT.* 
from MyTable as MT
   , YT
where  MT.ColumnX = 'X' 
and MT.ColumnY = YT.columnY