Bob*_*way 2 sql t-sql sql-server
我尝试针对两个大小不同的表运行此查询 - #temp大约是15,000行,而Member大约是70,000,000,其中大约68,000,000个没有ID 307.
SELECT COUNT(*)
FROM #temp
WHERE CAST(individual_id as varchar) NOT IN (
SELECT IndividualID
FROM Member m
INNER JOIN Person p ON p.PersonID = m.PersonID
WHERE CompanyID <> 307)
Run Code Online (Sandbox Code Playgroud)
这个查询运行了18个小时,然后我杀了它并尝试了其他的东西,这是:
SELECT IndividualID
INTO #source
FROM Member m
INNER JOIN Person p ON p.PersonID = m.PersonID
WHERE CompanyID <> 307
SELECT COUNT(*)
FROM #temp
WHERE CAST(individual_id AS VARCHAR) NOT IN (
SELECT IndividualID
FROM #source)
Run Code Online (Sandbox Code Playgroud)
在给我一个结果之前,这种情况持续了不到一秒钟.
我很惊讶这一点.我是一个中间层开发人员而不是SQL专家,而且我对引擎盖下发生的事情的理解有点模糊,但我会假设,因为我第一次尝试的子查询是完全相同的代码,要求与第二次尝试完全相同的数据,这些数据大致相同.
但那显然是错的.我无法查看原始查询的执行计划,以查看SQL Server正在尝试执行的操作.那么有人可以解释为什么将数据拆分到临时表中要快得多吗?
编辑:表模式和索引
该#temp表有两列,Individual_ID int和Source_Code varchar(50)
Member并且Person更复杂.它们分别有29列和13列,所以我真的不想全部发布它们.PersonID是一个int,是Person上的PK和成员上的FK.IndividualID是Person上的一列 - 这在查询中并不清楚.
在尝试提问之前,我尝试使用a LEFT JOIN而不是NOT IN.第二个查询的性能没有明显不同 - 两者都是亚秒级.在第一个查询中,我让它在停止之前运行了一个小时,假设它没有显着差异.
我还在#source上添加了索引,就像在原始表上一样,因此性能影响应该相同.
首先,您的查询有两个失败的错误.您正在转换为varchar(),但您没有包含长度参数.这不应该被允许!默认长度因上下文而异,您需要明确.
其次,您在不同的表中匹配两个键,它们看起来有不同的类型.外键引用应始终具有相同的类型.这会对性能产生很大影响.如果您正在处理具有数百万行的表,那么您需要注意数据结构.
要了解性能差异,您需要了解执行计划.这两个查询具有非常不同的执行计划.我的(有教养的)猜测是第一个版本版本使用嵌套循环连接算法.第二个版本使用更复杂的算法.在您的情况下,这可能是由于SQL Server能够维护表的统计信息.因此,实例化中间结果实际上有助于优化器生成更好的查询计划.
关于如何最好地编写这种逻辑的主题已经进行了很多调查. 以下是Aaron Bertrand对这个主题的非常好的讨论.
not exists在这种情况下,我同意Aaron的偏好:
SELECT COUNT(*)
FROM #temp t
WHERE NOT EXISTS (SELECT 1
FROM Member m JOIN
Person p
ON p.PersonID = m.PersonID
WHERE MemberID <> 307 and individual_id = t. individual_id
);
Run Code Online (Sandbox Code Playgroud)
但是,我不知道在这种特殊情况下这是否会有更好的表现.
| 归档时间: |
|
| 查看次数: |
140 次 |
| 最近记录: |