首页 > 解决方案 > 如何根据多列有效地选择 NON-NULL、NON-EMPTY 行?

问题描述

下面的查询有效,但是我想知道是否有办法优化它?就目前而言,它将为每个 OR 语句执行多个表扫描?

我在查询中采取防御措施的原因是,如果有人在 #{phone} 或 #{email} 中传递 NULL 或空字符串,它将进一步删除流程中的大量数据。因此,必须只为每个 OR 语句选择强匹配值。

SELECT ID 
FROM...

    WHERE (phone != '' AND phone IS NOT NULL AND phone = #{phone})

    OR (phone2 != '' AND phone2 IS NOT NULL AND phone2 = #{phone})

    OR (phone3 != '' AND phone3 IS NOT NULL AND phone3 = #{phone})

    OR (email != '' AND email IS NOT NULL AND email = #{email})

标签: sqlpostgresql

解决方案


我认为phone应该在应用层而不是数据库中对参数进行清理。

但是,如果它像您提到的那样至关重要,有时可以方便地采取一些安全措施,例如您正在使用的那些。如果是这种情况,则查询看起来不错。

从性能的角度来看,查询可以从索引中受益:

create index ix1 on t (phone);

create index ix2 on t (phone2);

create index ix3 on t (phone3);

create index ix4 on t (email);

现在,根据优化和数据直方图,引擎可能会选择避免索引。UNION如果是这种情况,您可以通过使用而不是OR(旧技巧)改写查询来促进上述索引的使用。例如:

SELECT ID 
WHERE (phone != '' AND phone IS NOT NULL AND phone = #{phone})
FROM...
UNION
SELECT ID 
WHERE (phone2 != '' AND phone2 IS NOT NULL AND phone2 = #{phone})
FROM...
UNION
SELECT ID 
WHERE (phone3 != '' AND phone3 IS NOT NULL AND phone3 = #{phone})
FROM...
UNION
SELECT ID 
WHERE (email != '' AND email IS NOT NULL AND email = #{email})

OR当谓词中没有 s 时,引擎使用索引要容易得多。然而,这个技巧在稍后执行UNIONs 时会付出代价。如果所选行数很少,则此成本应该是微不足道的。


推荐阅读