无法获取存储过程以将索引扫描更改为索引查找
Can't get stored procedure to change index scan to index seek
背景:我 运行正在 Azure 上的 Sql Server 2014 (12.0.2000.8) 上...
前几天我发现了一个方便的脚本,它显示了作为 "touching" 索引的 queries/stored 过程。我一直在寻找这个,因为我有一些性能很差的索引,但我找不到它们被调用的地方。
现在我有了这些信息,我一直在尝试 re-work 触及相关索引的过程。
在查看我的查询的执行计划时,它说它正在进行扫描,这显然不是最佳的。
将鼠标悬停在索引上会显示连接的输出列表,但没有谓词。
我继续使用该输出列表中的确切字段创建了一个索引。
这是正在 运行 的查询:
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
此列表中唯一具有扫描而不是搜索的连接是学校 table。它在 SchoolId 上加入,然后在 select 部分,它输出名称和会议。看起来很简单。
在我的第一次尝试中,我继续创建了这样的索引:
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)
但是它仍然在使用我创建的索引进行扫描。
我还应该注意什么才能尝试让此查询执行查找而不是扫描。
有关更多背景信息,这里是 table 定义的一个子集:
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
......
我知道有人会问,但我不知道该怎么做;如何将我的执行计划附加到问题中?
这里是 link 显示数据的页面:http://www.wrestlestat.com/rankings/dual/live
索引扫描并不总是坏事,特别是当你有一个非常小的 table 时。
但是绝对可以提高查询性能的方法是将 sub-queries
从 select
子句移至 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
并且结果集将与来自其他连接的结果集连接。更高效,更清洁。
您可以使用 LAG 和 LEAD 等窗口函数绕过 table 的自连接。
它可以导致更简单的执行计划。
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 将执行扫描而不是查找。
背景:我 运行正在 Azure 上的 Sql Server 2014 (12.0.2000.8) 上...
前几天我发现了一个方便的脚本,它显示了作为 "touching" 索引的 queries/stored 过程。我一直在寻找这个,因为我有一些性能很差的索引,但我找不到它们被调用的地方。
现在我有了这些信息,我一直在尝试 re-work 触及相关索引的过程。
在查看我的查询的执行计划时,它说它正在进行扫描,这显然不是最佳的。
将鼠标悬停在索引上会显示连接的输出列表,但没有谓词。
我继续使用该输出列表中的确切字段创建了一个索引。
这是正在 运行 的查询:
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
此列表中唯一具有扫描而不是搜索的连接是学校 table。它在 SchoolId 上加入,然后在 select 部分,它输出名称和会议。看起来很简单。
在我的第一次尝试中,我继续创建了这样的索引:
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)
但是它仍然在使用我创建的索引进行扫描。
我还应该注意什么才能尝试让此查询执行查找而不是扫描。
有关更多背景信息,这里是 table 定义的一个子集:
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
......
我知道有人会问,但我不知道该怎么做;如何将我的执行计划附加到问题中?
这里是 link 显示数据的页面:http://www.wrestlestat.com/rankings/dual/live
索引扫描并不总是坏事,特别是当你有一个非常小的 table 时。
但是绝对可以提高查询性能的方法是将 sub-queries
从 select
子句移至 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
并且结果集将与来自其他连接的结果集连接。更高效,更清洁。
您可以使用 LAG 和 LEAD 等窗口函数绕过 table 的自连接。 它可以导致更简单的执行计划。
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 将执行扫描而不是查找。