【问题标题】:Can't get stored procedure to change index scan to index seek无法获取存储过程以将索引扫描更改为索引查找
【发布时间】:2017-05-01 12:16:05
【问题描述】:

背景:我在 Azure 上的 Sql Server 2014 (12.0.2000.8) 上运行...

前几天我发现了一个方便的脚本,它显示了“接触”索引的查询/存储过程。我一直在寻找这个,因为我有一些表现很差的索引,但我找不到它们被调用的地方。

现在我有了这些信息,我一直在尝试重新处理涉及相关索引的 proc。

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

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

我继续创建了一个索引,其中包含该输出列表中的确切字段。

这是正在运行的查询:

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

【问题讨论】:

  • 表格的总行数是多少?
  • 仅仅因为有一个有效的索引并不总是意味着你会得到一个搜索。有时扫描非常好,尤其是在这种情况下,我猜测 School 中有很大一部分行被返回。
  • @M.Hassan 学校总数 = 597。此查询中返回的学校 = 77。
  • 对于少量行的优化器发现扫描的成本比seek要好。
  • 知道了,我只是讨厌看到我的扫描计数很高,而我的索引使用报告中的搜索计数却很低......我想我只需要处理它。

标签: sql-server azure indexing sql-server-2014 sql-execution-plan


【解决方案1】:

索引扫描并不总是一件坏事,特别是当您有一个非常小的表时。

但绝对可以提高查询性能的方法是将这些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 子句并使用连接,它将是@ 987654331@ 并且结果集将与来自其他连接的结果集连接。更高效、更清洁。

【讨论】:

  • @ganders 即使​​这不会给你一个搜索,它绝对是更好的选择,坚持下去。
【解决方案2】:

您可以使用诸如 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 将执行扫描而不是查找。

【讨论】:

    猜你喜欢
    • 2021-06-09
    • 2014-12-08
    • 1970-01-01
    • 2015-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-28
    • 1970-01-01
    相关资源
    最近更新 更多