Sql 在postgres中优化子查询

Sql 在postgres中优化子查询,sql,postgresql,subquery,Sql,Postgresql,Subquery,我在数据库中发现了一些可疑数据。我试图确定某个字段lastname是否正确。我在postgres中提出了以下问题: SELECT members."memberID", members.lastname FROM members WHERE members."memberID" NOT IN (SELECT members."memberID" FROM members

我在数据库中发现了一些可疑数据。我试图确定某个字段lastname是否正确。我在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]+)*');
子查询当前与普通名称和带有hypen的名称匹配。父查询应该显示与该模式不匹配的成员。目前,查询需要花费惊人的时间运行(我从未见过它完成)。我不知道为什么需要这么长时间,也不知道如何改进。

不存在 左连接/左连接为空 总结 :

PostgreSQL平等地对待
左连接
不存在
,对两者使用相同的执行计划(即上面示例中的哈希反连接)

至于
不在
中,这在语义上是不同的,因为它的逻辑是三价的,并且它可以返回NULL,PostgreSQL试图考虑到这一点,并将其自身限制为对子计划使用过滤器(如上面示例中的可散列结果集的散列子计划)

由于需要在哈希表中搜索两次每个缺少的值(第一次查找值,第二次查找空值),因此该方法的效率稍低

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

这就是为什么在PostgreSQL 8.4中应该始终使用
LEFT JOIN/IS NULL
NOT EXISTS
而不是
NOT in
来查找缺少的值

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

SELECT m."memberID", 
       m.lastname 
  FROM MEMBERS m 
 WHERE b.lastname ~* '[a-zA-z]+([-][a-zA-Z]+)*'
不存在 左连接/左连接为空 总结 :

PostgreSQL平等地对待
左连接
不存在
,对两者使用相同的执行计划(即上面示例中的哈希反连接)

至于
不在
中,这在语义上是不同的,因为它的逻辑是三价的,并且它可以返回NULL,PostgreSQL试图考虑到这一点,并将其自身限制为对子计划使用过滤器(如上面示例中的可散列结果集的散列子计划)

由于需要在哈希表中搜索两次每个缺少的值(第一次查找值,第二次查找空值),因此该方法的效率稍低

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

这就是为什么在PostgreSQL 8.4中应该始终使用
LEFT JOIN/IS NULL
NOT EXISTS
而不是
NOT in
来查找缺少的值

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

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

我喜欢OMG Ponies的答案,但如果
memberID
是唯一的(即PK),您可以完全删除子查询

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

(我删除了不区分大小写的操作符,因为regexp包含了这两种情况。)

我喜欢OMG Ponies的答案,但是如果
memberID
是唯一的(即PK),您可以完全删除子查询

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

(我删除了不区分大小写的操作符,因为regexp包含了这两种情况。)

@OMG我的编辑怎么了?@OMG:实际上。。。忽视我真傻:)@OMG我的编辑怎么了?@OMG:事实上。。。忽视我很傻:)我认为
不存在的版本中有输入错误
不存在的地方…
不存在的地方…
认为
不存在的版本中有打字错误<代码>不存在的位置…
不存在m.memberId的位置…