SQL 不使用索引的 Firebird 条件
SQL Firebird conditional where not using index
我正在使用 Firebird SQL 2.1 版。
我有一个 sql 查询字符串,其中传递了参数。
如果传递的值不在我手上,但如果传递了,它是正确的类型(Timestamp or else..)
现在我的查询如下所示:
select r.*
from TableA
where r.ACTION_DATE >= iif('2019-10-09 00:00:00' is null or '2019-10-09 00:00:00' = '', r.ACTION_DATE, '2019-10-09 00:00:00')
换句话说,当传递一个值时,我想加载操作日期大于“2019-10-09 00:00:00”的所有记录,否则获取所有记录。
我在列 ACTION_DATE 上有一个索引。对于我提到的查询,未应用索引!
对于没有应用索引的条件的相同查询:
select r.*
from TableA
where r.ACTION_DATE >= '2019-10-09 00:00:00'
几十年来没有使用 Interbase/Firebird,但我的猜测是右侧不是 sargable。
DBMS首先要得到行,得到r.ACTION_DATE
的值,计算右边的表达式,然后才能确定是否保留结果中的行,此时使用索引为时已晚(我们已经检索到该行,因此无需通过索引查找)。
尝试对表达式进行预求值,然后在 WHERE 子句中使用结果值(当然还有参数绑定等)。
另一件需要注意的事情是,索引只有在选择性足够好时才有用。如果检索的行太多(根据经验:超过整个 table 的 10%),那么即使索引可用,线性遍历整个 table 通常会更快。
列上的表达式通常会扼杀索引的使用。某些数据库可以处理显式 OR
:
select r.*
from TableA
where r.ACTION_DATE >= '2019-10-09 00:00:00' OR
'2019-10-09 00:00:00' IS NULL;
否则UNION ALL
能搞定:
select r.*
from TableA r
where r.ACTION_DATE >= '2019-10-09 00:00:00'
union all
select r.*
from TableA r
where '2019-10-09 00:00:00' IS NULL;
请注意,如果值为 NULL
,则第一个子查询 returns 没有行,因此没有重复行的危险。
我正在使用 Firebird SQL 2.1 版。
我有一个 sql 查询字符串,其中传递了参数。 如果传递的值不在我手上,但如果传递了,它是正确的类型(Timestamp or else..)
现在我的查询如下所示:
select r.*
from TableA
where r.ACTION_DATE >= iif('2019-10-09 00:00:00' is null or '2019-10-09 00:00:00' = '', r.ACTION_DATE, '2019-10-09 00:00:00')
换句话说,当传递一个值时,我想加载操作日期大于“2019-10-09 00:00:00”的所有记录,否则获取所有记录。
我在列 ACTION_DATE 上有一个索引。对于我提到的查询,未应用索引!
对于没有应用索引的条件的相同查询:
select r.*
from TableA
where r.ACTION_DATE >= '2019-10-09 00:00:00'
几十年来没有使用 Interbase/Firebird,但我的猜测是右侧不是 sargable。
DBMS首先要得到行,得到r.ACTION_DATE
的值,计算右边的表达式,然后才能确定是否保留结果中的行,此时使用索引为时已晚(我们已经检索到该行,因此无需通过索引查找)。
尝试对表达式进行预求值,然后在 WHERE 子句中使用结果值(当然还有参数绑定等)。
另一件需要注意的事情是,索引只有在选择性足够好时才有用。如果检索的行太多(根据经验:超过整个 table 的 10%),那么即使索引可用,线性遍历整个 table 通常会更快。
列上的表达式通常会扼杀索引的使用。某些数据库可以处理显式 OR
:
select r.*
from TableA
where r.ACTION_DATE >= '2019-10-09 00:00:00' OR
'2019-10-09 00:00:00' IS NULL;
否则UNION ALL
能搞定:
select r.*
from TableA r
where r.ACTION_DATE >= '2019-10-09 00:00:00'
union all
select r.*
from TableA r
where '2019-10-09 00:00:00' IS NULL;
请注意,如果值为 NULL
,则第一个子查询 returns 没有行,因此没有重复行的危险。