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

Posted

技术标签:

【中文标题】创建最佳查询以查找仅在一个表中的记录【英文标题】:Create optimum query to find records that are in only one table 【发布时间】:2009-06-15 22:36:09 【问题描述】:

假设我正在构建这个联系人管理系统。有一个 USER 表和一个 CONTACT_INFO 表。 对于每个用户,我可以有零个或多个 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 记录时更新它不应该是昂贵的,性能方面的。

一如既往,我们非常感谢您的反馈。

【问题讨论】:

您应该尝试以下几个选项,然后确定每个选项的查询计划和性能,然后选择最好的一个。 我们在谈论哪个 DBMS? 【参考方案1】:

最简单的方法是:

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

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

【讨论】:

我测试过的优化器将其视为简单的不存在。 (但无论如何,这对于很多情况来说都是一种很棒的技术,而且更便携,这意味着它可以在旧版本的 mysql 中使用。)【参考方案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

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

【讨论】:

【参考方案3】:

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

【讨论】:

为什么要删除 DISTINCT? 因为它实际上可能会计算值的聚合列表。它真正需要做的就是查看索引,看看是否有任何价值——它只需要找到第一个。【参考方案4】:

至少在 oracle 中,我获得了更好的性能使用

where 0 = (select count(*) from CONTACT_INFO c where...)

而不是 NOT IN 子句。

【讨论】:

以上是关于创建最佳查询以查找仅在一个表中的记录的主要内容,如果未能解决你的问题,请参考以下文章

Oracle查询查找表中不存在的记录?

强制查询为查找表中的每个值生成记录

Microsoft Access 中的选择查询在另一个表中查找返回错误结果的记录

在单个查询中查找各种表中的总记录

C# EF 在另一个表中查找数据的最佳方法

sql查询 如何获取查找某ID的一条记录在表中是第几条记录