在连接表 B 中查找表 A 中没有记录的行
Posted
技术标签:
【中文标题】在连接表 B 中查找表 A 中没有记录的行【英文标题】:Find rows from table A without record in joined table B 【发布时间】:2017-07-05 07:53:29 【问题描述】:我有两个表,分别称为 Employee(列:Id、Name)和 DataSource(列:Id、EmployeeId、DataSourceName)。
每个员工都可以导出到零个或多个数据源并想象以下情况:
员工表
+----+-------------+
| Id | Name |
+----+-------------+
| 1 | Ivan |
| 2 | Adam |
+----+-------------+
数据源表:
+----+---------------------------------+
| Id | EmplpoyeeId | DataSourceName |
+----+---------------------------------+
| 1 | 1 | Source1 |
| 2 | 1 | Source2 |
| 3 | 2 | Source2 |
+----+---------------------------------+
我需要一个查询来确定哪个员工没有被导出到“Source1”(在这种情况下,结果应该是“Adam”,因为他只被导出到了“Source2”)。
表 Employee 和 DataSource 可以有大量记录(数千条)。
有几种技术可以确定它,我们需要找到性能最佳的技术。我想到的很少:
左连接:
SELECT Employee.Id
FROM Employee
LEFT JOIN DataSource ON DataSource.EmployeeId = Employee.Id AND DataSource.DataSourceName = 'Source1'
WHERE DataSource.Id IS NULL
内部选择:
SELECT Employee.Id
FROM Employee
WHERE NOT EXIST (SELECT NULL FROM DataSource WHERE DataSource.EmployeeId = Employee.Id AND DataSource.DataSourceName = 'Source1')
例外:
SELECT Employee.ID
FROM Employee
EXCEPT
SELECT Employee.Id
FROM Employee
INNER JOIN DataSource ON DataSource.EmployeeId = Employee.Id AND DataSource.DataSourceName = 'Source1'
在开始对它们进行基准测试之前,我想问一下我是否应该考虑更多方法(并且可能表现良好)。能否请您分享您对最佳性能查询的想法。
【问题讨论】:
您必须只进行测试,但是 WHERE NOT EXISTS “应该”更快,因为它不需要进行完全连接并且可以提前退出......但这将取决于一些因素,所以你真的需要测试 我想是的,我们也可以在找到第一条记录后退出(通过使用 SELECT TOP 1) - 这也可能适用于 WHERE NOT EXISTS 如果在NOT EXIST()中使用select,则不需要使用TOP 1,找到一条记录后会自动停止 我的意思是在顶部查询中使用 TOP 1 而不是在嵌套查询中,因此它声明:SELECT TOP 1 Employee.Id FROM Employee WHERE NOT EXIST ... 【参考方案1】:如果您需要进一步阅读该主题,这篇文章很好;
http://www.sqlinthewild.co.za/index.php/2010/03/23/left-outer-join-vs-not-exists/
这表明 NOT EXISTS 会表现得更好,因为它不需要完成完全连接(使用反半连接而不是半连接);
“这是这两者之间的主要区别。当使用 LEFT OUTER JOIN ... IS NULL 技术时,SQL 无法判断您只是在检查不存在。优化器还不够聪明(还)。因此它确实完整的连接,然后过滤。NOT EXISTS 过滤器作为连接的一部分。"
【讨论】:
感谢@Milney 我也想知道第三个选项 - 例外,我已将其添加到我的问题中。你觉得这个怎么样? @jabko87 - 这实际上在逻辑上是不同的 - 例如,EXCEPT 将过滤掉重复项(就像您应用了 DISTINCT),因为它是基于集合的操作,如果您使用它,它也会将 NULL 视为值拥有他们。所以你可以使用 except 但必须考虑它是否真的在做同样的事情。我认为它不会更快(因为再次 - 它必须处理整个结果集)所以我会选择 NOT EXISTS .但唯一确定(使用您的特定数据配置文件)的方法是测试!只需运行几次,然后测量差异(使用 SET STATISTICS TIME ON) @jabko87 对性能而言,最重要的是在列(EmployeeId 和 DataSourceName)上有一个索引,并提供最新的统计信息……如果你有,它们的性能都应该可以接受以上是关于在连接表 B 中查找表 A 中没有记录的行的主要内容,如果未能解决你的问题,请参考以下文章