【问题标题】:Performance Issue in Left outer join Sql server左外连接 SQL 服务器中的性能问题
【发布时间】: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。

标签: sql sql-server sql-server-2012


【解决方案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】:
    1. latest_Rev 应该是 Bit 类型(布尔等效),我对性能更好(详情 here
    2. 可能你能在 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
    )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-21
      相关资源
      最近更新 更多