创建最佳查询以查找仅在一个表中的记录

时间:2009-06-15 22:36:09

标签: sql query-optimization

所以我想说我正在构建这个联系人管理系统。有一个USER表和一个CONTACT_INFO表。 对于每个USER,我可以有零个或多个CONTACT_INFO记录。我定义它的方式,我在CONTACT_INFO表中设置了一个外键,指向相关的USER记录。

我想搜索没有CONTACT_INFO记录的所有USER记录。

我希望可以这样做:

SELECT * FROM user u WHERE u.user_id NOT IN (SELECT DISTINCT c.user_id FROM CONTACT_INFO);

我担心的是,随着表的增长,此查询的性能会显着下降。

我正在玩的一个想法是在USER表中添加一个列,说明它是否有任何CONTACT_INFO记录。另外,我想知道,如果在CONTACT_INFO中插入任何记录,DBMS必须验证记录是否存在,为了验证而已经访问该记录并因此更新它,当我更新CONTACT_INFO记录时不应该这是代价高昂的,性能方面的。

一如既往,感谢您的反馈。

4 个答案:

答案 0 :(得分:3)

最简单的方法是:

SELECT (...) 
FROM user u
LEFT OUTER JOIN CONTACT_INFO c
ON u.user_id = c.user_id
WHERE c.user_id IS NULL

它看起来更笨重,但应该更好地扩展。

答案 1 :(得分:2)

从我的测试中,以下内容比BradC的方法更快:

select (...)
from user u
where not exists (select null from CONTACT_INFO c where u.user_id = c.user_id)

这可能是因为编译器本身不得不进行转换,我不知道。

但是,Le Dorfier原则上是正确的:如果您已经在数据库上设置了索引(即两个user_id列都应该被编入索引),那么您的答案和大多数这些响应将非常快,无论如何您在数据库中拥有的许多记录。

顺便提一下,如果您正在寻找一种方法来获取列出用户的查询以及“HasContactInfo”布尔值,您可以执行以下操作:

select u.(...), 
  (case when exists (select null from CONTACT_INFO c where c.user_id = u.user_id) then 1
        else null
        end) has_contact_info
from user u

这个第二个解决方案在您的情况下可能没有用,但我发现它比一些我认为会自动优化的更简单的查询要快得多。

答案 2 :(得分:1)

你有理由认为性能会降低吗?这是SQL中最有效的查询类型之一。但放弃DISTINCT。

答案 3 :(得分:1)

至少在oracle中,我使用

获得了更好的性能

其中0 =(从CONTACT_INFO c中选择计数(*),其中......)

而不是NOT IN子句。