我在数据库中发现了一些可疑数据。我试图确定某个字段,姓氏是否正确。我在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]+)*');
子查询当前与普通名称和名称匹配。父查询应显示与该模式不匹配的成员。目前,查询需要花费大量的时间来运行(我从未见过它完成)。我不确定为什么需要这么长时间或如何改进它。
答案 0 :(得分:3)
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");
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
PostgreSQL同等对待
LEFT JOIN
和NOT EXISTS
,使用相同的执行计划(例如上面的示例中的Hash Anti Join)。至于
NOT IN
,由于它的逻辑是三价的并且它可以返回NULL,它在语义上是不同的,PostgreSQL试图将此考虑在内并限制自己使用针对子计划的过滤器(哈希的哈希子计划)结果集,如上例所示。)由于需要两次搜索哈希表中的每个缺失值(第一次查找值,第二次查找NULL),此方法效率稍差。
优化程序在决定列表不适合内存时可以求助的普通子计划是非常低效的,并且应该像瘟疫一样避免有可能使用它的查询。
这就是为什么在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]+)*'
答案 1 :(得分:2)
我喜欢OMG小马的回答,但如果 memberID
是唯一的(即PK),你可以完全放弃子查询。
SELECT members."memberID",
members.lastname
FROM members
WHERE members.lastname !~ '[a-zA-Z]+([-][a-zA-Z]+)*';
(我删除了不区分大小写的运算符,因为regexp涵盖了两种情况。)