了解sql server索引

6ioyuze2  于 2021-08-09  发布在  Java
关注(0)|答案(1)|浏览(367)

抱歉,邮件太长了。我们有一个大约每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行。
我们有两个技术团队,就性能问题进行联络。一个团队建议表中没有支持此提取查询的索引,向date列添加索引将使查询运行得更平稳。
另一个团队说,代码需要重新编写,因为“向日期列添加索引会增加问题,因为这是一个过于生硬的工具”。他们还建议创建一个索引视图,以便我们从中提取数据,而不是转到实际的表本身。
关于这一点,最好的办法是什么?只是想得到一些意见,因为我的印象是,如果用于筛选的列上根本没有索引,那么代码是如何编写的并不重要?
感谢你的任何想法!

jc3wubiy

jc3wubiy1#

OR 对于索引来说,s是非常糟糕的逻辑。如果每列上都有单独的索引,则可以将其转换为 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

相关问题