在postgres中调整子查询

时间:2011-05-15 17:39:02

标签: sql postgresql subquery

我在数据库中发现了一些可疑数据。我试图确定某个字段,姓氏是否正确。我在postgres中提出了以下查询:

SELECT members."memberID", 
       members.lastname 
  FROM members 
 WHERE members."memberID" NOT IN (SELECT members."memberID" 
                                    FROM members 
                                   WHERE members.lastname ~* '[a-zA-z]+([-][a-zA-Z]+)*');

子查询当前与普通名称和名称匹配。父查询应显示与该模式不匹配的成员。目前,查询需要花费大量的时间来运行(我从未见过它完成)。我不确定为什么需要这么长时间或如何改进它。

2 个答案:

答案 0 :(得分:3)

NOT EXISTS

SELECT m."memberID", 
       m.lastname 
  FROM MEMBERS m 
 WHERE NOT EXISTS (SELECT NULL
                     FROM MEMBERS b
                    WHERE b.lastname ~* '[a-zA-z]+([-][a-zA-Z]+)*'
                      AND b."memberID" = m."memberID");

LEFT JOIN / IS NULL

   SELECT m."memberID", 
          m.lastname 
     FROM MEMBERS m 
LEFT JOIN MEMBERS b ON b."memberID" = m."memberID"
                   AND b.lastname ~* '[a-zA-z]+([-][a-zA-Z]+)*'
    WHERE b."memberID" IS NULL

摘要

Quote

  

PostgreSQL同等对待LEFT JOINNOT EXISTS,使用相同的执行计划(例如上面的示例中的Hash Anti Join)。

     

至于NOT IN,由于它的逻辑是三价的并且它可以返回NULL,它在语义上是不同的,PostgreSQL试图将此考虑在内并限制自己使用针对子计划的过滤器(哈希的哈希子计划)结果集,如上例所示。)

     

由于需要两次搜索哈希表中的每个缺失值(第一次查找值,第二次查找NULL),此方法效率稍差。

     

优化程序在决定列表不适合内存时可以求助的普通子计划是非常低效的,并且应该像瘟疫一样避免有可能使用它的查询。

     

这就是为什么在PostgreSQL 8.4中应该始终使用LEFT JOIN / IS NULLNOT EXISTS而不是NOT IN来查找缺失值。

附录

但正如Andrew Lazarus指出的那样,如果MEMBERS表中没有memberid重复,则查询只需要:

SELECT m."memberID", 
       m.lastname 
  FROM MEMBERS m 
 WHERE b.lastname ~* '[a-zA-z]+([-][a-zA-Z]+)*'

答案 1 :(得分:2)

我喜欢OMG小马的回答,但如果 memberID是唯一的(即PK),你可以完全放弃子查询。

SELECT members."memberID", 
       members.lastname 
  FROM members 
 WHERE members.lastname !~ '[a-zA-Z]+([-][a-zA-Z]+)*';

(我删除了不区分大小写的运算符,因为regexp涵盖了两种情况。)