首页 > 解决方案 > 了解 SQL Server 索引

问题描述

对不起,很长的帖子。我们有一个每 10 分钟左右运行一次的数据提取,用于将数据从源表传输到我们的数据仓库。

代码看起来像这样:

SELECT 
    Column1,
    Column2,
    Column3,
    Column4
FROM 
    dbo.Table
WHERE
    LastModifiedDate > @LastRun
    OR CreatedDate > @LastRun
    OR CancelledDate > @LastRun
    OR DeletedDate > @LastRun

@LastRun参数通过 SSIS 包传递,并包含我们运行的最后一个日期时间(因此我们只带回我们需要的内容)。

尽管每次只返回 50-70 行,但此代码在源系统上运行非常缓慢。

我们有 2 个技术团队就性能问题进行联络。一个团队建议表上没有索引来支持此提取查询,并且向日期列添加索引将使查询运行更顺畅。

另一个团队说代码需要重新编写,因为“将索引添加到日期列会增加问题,因为它是一个过于生硬的工具”。他们还建议为我们创建一个索引视图来从中提取数据,而不是转到实际的表本身。

对此最好的方法是什么?只是想真正获得意见,因为我的印象是,如果用于过滤的列根本没有索引,那么代码的编写方式并不重要?

欣赏任何想法!

标签: sqlsql-server-2012

解决方案


ORs 对于索引来说是非常糟糕的逻辑。如果每列都有单独的索引,则可以将其转换为union all

select . . .
from t
where LastModifiedDate > @LastRun
union all
select . ..
from t
where CreatedDate > @LastRun and
      not (LastModifiedDate > @LastRun)
union all
select . ..
from t
where CancelledDate > @LastRun and
      not (LastModifiedDate > @LastRun and CreatedDate > @LastRun )
union all
select . ..
from t
where DeletedDate > @LastRun and
      not (LastModifiedDate > @LastRun and CreatedDate > @LastRun and CancelledDate > @LastRun);

注意:如果列可以为空,逻辑会稍微复杂一些。

这种方法也很麻烦,因为需要重复查询四次,并且对所有四列都有索引。如果 SQL Server ——以其无限的智慧——决定不为一个子查询使用索引,你就会陷入性能更差的解决方案中。

另一种方法是在计算列上使用索引:

alter table t add most_recent_date as
    (case when LastModifiedDate >= CreatedDate and LastModifiedDate >= CancelledDate and LastModifiedDate >= DeletedDate then LastModifiedDate
          when CreatedDate >= CancelledDate and CreatedDate >= DeletedDate then CreatedDate
          when CancelledDate >= DeletedDate then CancelledDate
          else DeletedDate
     end) persisted;

create index idx_most_recent_date on t(most_recent_date);

请注意,如果任何日期都可以,则计算列逻辑会稍微复杂一些NULL。如果这些设置在触发器中,则只需修改触发器以使最新日期保持最新可能会更简单。

然后,您可以将查询表述为:

where most_recent_date > @LastRun

推荐阅读