左外连接 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 - 显然LAGNot 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 服务器中的性能问题的主要内容,如果未能解决你的问题,请参考以下文章

netezza 左外连接查询性能

oracle的SQL语句中的(+) 左外连接

左外连接和右外连接的区别

LINQ to SQL 执行联合和左外连接

Linq to Sql:多个左外连接

具有多个左外连接的 SQL Server 查询挂起