假设我有一个数据库设置和一个名为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应用程序,但我想这个问题比那个更通用。
答案 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