0

背景:我在Azure上的SQL服务器2014(12.0.2000.8)上运行...不能获取存储过程来更改索引扫描索引查找

我发现了一个方便的脚本有一天这表明“触摸”索引的查询/存储过程。我一直在寻找这一段时间,因为我有一些表现非常差的索引,但我找不到它们被称为的位置。

现在我有了这些信息,我一直在尝试重新触摸正在触及索引的过程。

在查看我的查询的执行计划时,它说它正在执行显然不是最佳的扫描。

将鼠标悬停在索引上将显示连接的输出列表,但不显示谓词。

我继续前进,并创建了一个具有输出列表中确切字段的索引。

下面是正在运行查询:

declare @season int = 2017 

select s.SchoolId, 
     s.Name [SchoolName], 
     s.Conference, 
     tr.DualRank [Rank], 
     convert(varchar(2), tr.DualWins) + ' - ' + convert(varchar(2), tr.DualLosses) [Record], 
     tr.RankingDate, 
     case when tr.WeekNumber = 0 then null 
       else 
        (select trx.DualRank from dbo.TeamRankings trx where trx.Season = tr.Season and trx.WeekNumber = (tr.WeekNumber - 1) and trx.SchoolId = tr.SchoolId) 
        - tr.DualRank 
     end [Trend], 
     (select trx.DualRank from dbo.TeamRankings trx where trx.Season = tr.Season and trx.WeekNumber = (tr.WeekNumber - 1) and trx.SchoolId = tr.SchoolId) [PreviousWeek] 
from dbo.TeamRankings tr 
join dbo.School s on s.SchoolId = tr.SchoolId 
where tr.Season = @season 
and  tr.IsCurrent = 1 
order by tr.DualRank 

只有在此列表中,有一个扫描,而不是追求的是一个到校表连接。它加入了SchoolId,然后在选择部分输出名称和会议。看起来很简单。

在我第一次尝试,我继续创建了索引是这样的:

create nonclustered index idx_NC_School_SchoolId_incs on dbo.School (SchoolId asc) include (Name, Conference) 

但仍然导致了扫描。我的第二次尝试是这样做的:

create nonclustered index idx_NC_School_SchoolId_Name_Conference on dbo.School (SchoolId asc, Name asc, Conference asc) 

但是,仍然是利用我创建的索引进行扫描。

还有什么我应该看看试图让这个查询做一个寻找而不是扫描。

欲了解更多背景资料,这里的表定义的一个子集:

dbo.School 
SchoolId int identity(1,1) primary key, 
Name varchar(100) not null, 
Conference varchar(100) not null -- will soon change this to a lookup table 
...... 

我知道有人会问,但我无法弄清楚如何做到这一点;我如何将执行计划附加到问题上?

这里到页面的链接,其中所显示的数据:http://www.wrestlestat.com/rankings/dual/live

+0

表中的总行数是多少? –

+0

仅仅因为有一个有效的索引并不总是意味着你会得到一个寻求。有时候扫描是完全正常的,特别是在这种情况下,我猜测学校里有很大一部分行被返回。 –

+0

@ M.Hassan total schools = 597.在此查询中返回的学校= 77. – ganders

回答

0

索引扫描并不总是一件坏事,特别是当你有一个非常小桌子。

但东西绝对可以提高查询性能是这些sub-queriesselect从句移至from和使用join

......

declare @season int = 2017 

select s.SchoolId, 
     s.Name [SchoolName], 
     s.Conference, 
     tr.DualRank [Rank], 
     convert(varchar(2), tr.DualWins) + ' - ' + convert(varchar(2), tr.DualLosses) [Record], 
     tr.RankingDate, 
     CASE WHEN tr.WeekNumber = 0 then null 
      ELSE trx.DualRank - tr.DualRank end [Trend], 
     trx.DualRank [PreviousWeek] 
from dbo.TeamRankings tr 
Inner join dbo.School  s on s.SchoolId = tr.SchoolId 

Left join dbo.TeamRankings trx ON trx.Season = tr.Season 
           and trx.WeekNumber = (tr.WeekNumber - 1) 
           and trx.SchoolId = tr.SchoolId 
where tr.Season = @season 
and  tr.IsCurrent = 1 
order by tr.DualRank 

当你有select子句中sub-query,该sub-query是由outer query返回的每一行执行的,如果你把它移动到from条款和使用联接,这将是executed once,结果集将加入来自其他联结的结果集。更高效和更清洁。

+0

我实际上是在我周围玩的时候这样做的...... – ganders

+0

@ganders即使这不会给你一个寻求,但它绝对是更好的选择,坚持下去。 –

0

您可以使用LAG和LEAD等窗口函数来自动加入表格。 它可以导致更简单的执行计划。

declare @season int = 2017 

select 
    s.SchoolId, 
    s.Name [SchoolName], 
    s.Conference, 
    tr.DualRank [Rank], 
    convert(varchar(2), tr.DualWins) + ' - ' + convert(varchar(2), tr.DualLosses) [Record], 
    tr.RankingDate, 
    CASE WHEN tr.WeekNumber = 0 THEN NULL ELSE tr.DualRank - LAG(tr.DualRank,1,0) OVER(Partition BY tr.Season,tr.SchoolId ORDER BY trx.WeekNumber) END AS [Trend], 
    LAG(tr.DualRank,1,0) OVER(Partition BY tr.Season,tr.SchoolId ORDER BY trx.WeekNumber) AS [PreviousWeek] 

from  
    dbo.TeamRankings tr 
     join dbo.School s on s.SchoolId = tr.SchoolId 
where 
    tr.Season = @season 
    and  
    tr.IsCurrent = 1 
order by 
    tr.DualRank 

当您使用

trx.WeekNumber = (tr.WeekNumber - 1) 

你改变tr.WeekNumber的价值,因此它是存储在索引中的值不同,所以SQL将进行扫描,而不是寻求。