创建最佳查询以查找仅在一个表中的记录
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 子句。
【讨论】:
以上是关于创建最佳查询以查找仅在一个表中的记录的主要内容,如果未能解决你的问题,请参考以下文章