左外连接 SQL 服务器中的性能问题
Posted
技术标签:
【中文标题】左外连接 SQL 服务器中的性能问题【英文标题】:Performance Issue in Left outer join Sql server 【发布时间】:2017-06-16 07:53:48 【问题描述】:在我的项目中,我需要根据同一张表中的旧版本和新版本来查找差异任务。
id | task | latest_Rev
1 A N
1 B N
2 C Y
2 A Y
2 B Y
预期结果:
id | task | latest_Rev
2 C Y
所以我尝试了以下查询
Select new.*
from Rev_tmp nw with (nolock)
left outer
join rev_tmp old with (nolock)
on nw.id -1 = old.id
and nw.task = old.task
and nw.latest_rev = 'y'
where old.task is null
当我的表有超过 20k 条记录时,此查询需要更多时间吗? 如何减少时间?
在我的公司不允许使用子查询
【问题讨论】:
不仅仅是什么?你的表是如何索引的?查询计划是什么? 不允许使用子查询听起来很奇怪。您可以使用 CTE 吗?派生表?为什么允许你使用 NOLOCK? 我的表没有包含所有主字段的聚集索引。它是一个规则。 @JamesZ。 【参考方案1】:使用LAG
函数去除自连接
SELECT *
FROM (SELECT *,
CASE WHEN latest_Rev = 'y' THEN Lag(latest_Rev) OVER(partition BY task ORDER BY id) ELSE NULL END AS prev_rev
FROM Rev_tmp) a
WHERE prev_rev IS NULL
【讨论】:
什么性能更好?我的“不存在”还是你的“滞后”?在大桌子上,我认为它“不存在”,您对此有何看法? @Esperento57 - 显然LAG
、Not exists
需要扫描/查找表两次。
是的,但你也使用“case”和临时表作为你的 where ;)
@Esperento57 - 它不是临时表。它被称为派生表,它不会在磁盘中存储任何内容。使用CASE
仍然比两次敲桌子要好;)
如果他在 latest_Rev 字段上有索引,您的查询可能不会用于滞后,我不知道:P【参考方案2】:
我的回答假设
您无法更改索引 您不能使用子查询 所有字段都单独编入索引如果您查看查询,真正减少结果集的唯一值是latest_rev='Y'
。如果你要消除这种情况,你肯定会得到一个表扫描。所以我们希望使用索引来评估该条件。不幸的是,只有值“Y”和“N”的字段可能会被忽略,因为它的选择性很差。如果您诱使 SQL Server 使用它,可能会获得更好的性能。如果latest_rev
上的索引被称为idx_latest_rev
,那么试试这个:
Set transaction isolated level read uncommitted
Select new.*
from Rev_tmp nw with (index(idx_latest_rev))
left outer
join rev_tmp old
on nw.id -1 = old.id
and nw.task = old.task
where old.task is null
and nw.latest_rev = 'y'
【讨论】:
【参考方案3】:-
latest_Rev 应该是 Bit 类型(布尔等效),我对性能更好(详情 here)
可能你能在 id、task 上添加索引吗
, latest_Rev 列
你可以试试这个查询(用不存在替换左外)
Select *
from Rev_tmp nw
where nw.latest_rev = 'y' and not exists
(
select * from rev_tmp old
where nw.id -1 = old.id and nw.task = old.task
)
【讨论】:
以上是关于左外连接 SQL 服务器中的性能问题的主要内容,如果未能解决你的问题,请参考以下文章