无法获取存储过程以将索引扫描更改为索引查找

时间:2016-12-15 19:25:52

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

背景:我在Azure上运行Sql Server 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)

但是STILL正在利用我创建的索引进行扫描。

我还应该考虑尝试让此查询进行搜索而不是扫描。

有关更多背景信息,请参阅表定义的子集:

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

2 个答案:

答案 0 :(得分: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

如果sub-query子句中有select,则sub-query会为outer query返回的每一行执行from,如果将其移至executed once }子句和使用连接,它将是# -*- coding: utf-8 -*- """Add permissions for proxy model. This is needed because of the bug https://code.djangoproject.com/ticket/11154 in Django (as of 1.6, it's not fixed). When a permission is created for a proxy model, it actually creates if for it's base model app_label (eg: for "article" instead of "about", for the About proxy model). What we need, however, is that the permission be created for the proxy model itself, in order to have the proper entries displayed in the admin. """ from __future__ import unicode_literals, absolute_import, division import sys from django.contrib.auth.management import _get_all_permissions from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType from django.core.management.base import BaseCommand from django.apps import apps from django.utils.encoding import smart_text class Command(BaseCommand): help = "Fix permissions for proxy models." def handle(self, *args, **options): for model in apps.get_models(): opts = model._meta ctype, created = ContentType.objects.get_or_create( app_label=opts.app_label, model=opts.object_name.lower(), defaults={'name': smart_text(opts.verbose_name_raw)}) for codename, name in _get_all_permissions(opts): p, created = Permission.objects.get_or_create( codename=codename, content_type=ctype, defaults={'name': name}) if created: sys.stdout.write('Adding permission {}\n'.format(p)) ,结果集将与来自其他连接的结果集连接。更高效,更清洁。

答案 1 :(得分: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将执行扫描而不是搜索。