Sql server 为什么即使我在IGroupes表上有索引,也要进行表扫描?

Sql server 为什么即使我在IGroupes表上有索引,也要进行表扫描?,sql-server,tsql,sql-server-2012,rdbms,Sql Server,Tsql,Sql Server 2012,Rdbms,这是我的疑问: exec sp_executesql N'set arithabort off;set statistics time on; set transaction isolation level read uncommitted;With cte as (Select peta_rn = ROW_NUMBER() OVER (ORDER BY d.LastStatusChangedDateTime desc )

这是我的疑问:

exec sp_executesql N'set arithabort off;set statistics time on; set transaction isolation level read uncommitted;With cte as (Select peta_rn = ROW_NUMBER() OVER (ORDER BY  d.LastStatusChangedDateTime  desc )  
                                                , d.DocumentID,
                                                d.IsReEfiled, d.IGroupID, d.ITypeID, d.RecordingDateTime, d.CreatedByAccountID, d.JurisdictionID, 
                                                d.LastStatusChangedDateTime as LastStatusChangedDateTime
                                                ,  d.IDate, d.InstrumentID, d.DocumentStatusID
                                                , u.Username
                                                , it.Abbreviation AS ITypeAbbreviation
                                                , ig.Abbreviation AS IGroupAbbreviation,
                                                d.DocumentDate                                               
                                From Documents d                             
                                Inner Join ITypes it  on it.ITypeID = d.ITypeID
                                 Inner Join Users u on d.UserID = u.UserID Inner Join IGroupes ig on ig.IGroupID = d.IGroupID
                                Where 1=1  And  (  d.DocumentStatusID = 9  ) ) Select cte.DocumentID, 
                                cte.IsReEfiled, cte.IGroupID, cte.ITypeID, cte.RecordingDateTime, cte.CreatedByAccountID, cte.JurisdictionID, 
                        cte.LastStatusChangedDateTime as LastStatusChangedDateTime
                        ,  cte.IDate, cte.InstrumentID, cte.DocumentStatusID,cte.IGroupAbbreviation, cte.Username, j.JDAbbreviation, inf.DocumentName,
                       cte.ITypeAbbreviation, cte.DocumentDate, ds.Abbreviation as DocumentStatusAbbreviation,  ds.Name as DocumentStatusName,
                        ( SELECT CAST(CASE WHEN cte.DocumentID = (
                                SELECT TOP 1 doc.DocumentID
                                FROM  Documents doc
                                WHERE doc.JurisdictionID = cte.JurisdictionID
                                        AND doc.DocumentStatusID = cte.DocumentStatusID
                                ORDER BY LastStatusChangedDateTime) 
                            THEN 1
                            ELSE 0
                        END AS BIT)
                        ) AS CanChangeStatus ,

                        Upper((Select Top 1 Stuff( (Select ''='' + dbo.GetDocumentNameFromParamsWithPartyType(Business, FirstName, MiddleName, LastName, t.Abbreviation, NameTypeID, pt.Abbreviation, IsGrantor, IsGrantee)  From DocumentNames dn
                                Left Join Titles t
                                    on dn.TitleID = t.TitleID               
                                Left Join PartyTypes pt
                                    On pt.PartyTypeID = dn.PartyTypeID
                                        Where DocumentID = cte.DocumentID
                                            For XML PATH('''')),1,1,''''))) as FlatDocumentName, (SELECT COUNT(*) FROM CTE) AS TotalRecords

                        FROM cte Left Join DocumentStatuses ds On
                        cte.DocumentStatusID = ds.DocumentStatusID Left Join InstrumentFiles inf On cte.DocumentID = inf.DocumentID 
                    Left Join Jurisdictions j on j.JurisdictionID = cte.JurisdictionID Where 1=1 And 
                    peta_rn>@7 AND peta_rn<=@8 Order by peta_rn set statistics time off; ',N'@0 int,@1 int,@2 int,@3 int,@4 int,@5 int,@6 int,@7 int,@8 int',
                    @0=1,@1=5,@2=9,@3=1,@4=5,@5=9,@6=1,@7=97500,@8=97550
但请看它使用的是表扫描。这次手术花了我太多钱
i组
表只有7行,而
文档
表大约有98K条记录。然而,当我在
d.IGroupID=ig.IGroupID
上加入时,它显示了超过600K的实际行数!这就是问题所在。请参见随附的屏幕截图:

如果有人对完整的查询计划xml感兴趣,请参见:


感谢您的帮助。谢谢

在这种情况下,表扫描可能比使用
i组
表上的任何索引更有效。 如果您认为表扫描操作是此查询中的瓶颈(尽管成本为3%,我不确定是否是),您可以尝试将
PK\u igroups
修改为聚集索引,也可以尝试类似索引的操作

CREATE UNIQUE NONCLUSTERED INDEX [IX_IGroupes_IGroupID]
    ON [dbo].[IGroupes] ([IGroupID]) INCLUDE ([Abbreviation])

在这种情况下,表扫描可能比使用
igroups
表上的任何索引更有效。 如果您认为表扫描操作是此查询中的瓶颈(尽管成本为3%,我不确定是否是),您可以尝试将
PK\u igroups
修改为聚集索引,也可以尝试类似索引的操作

CREATE UNIQUE NONCLUSTERED INDEX [IX_IGroupes_IGroupID]
    ON [dbo].[IGroupes] ([IGroupID]) INCLUDE ([Abbreviation])
您在
igroups
上拥有的3个索引(PK除外)都不能帮助此查询,因为您没有在where或join子句中使用这些字段。除非其他查询需要这些索引,否则我将删除它们。他们只是给查询优化器更多的选择来测试(和拒绝)

主键
PK_igroups
上的索引应进行聚类。这将允许它进行索引查找(或书签查找)。如果由于其他原因无法对其进行聚集,请尝试按顺序在
IGroupID
缩写
上创建索引(或在现有PK索引中包含
缩写
列)

如果它仍然没有选择正确的索引,您可以使用提示,例如
WITH(index(0))
WITH(index('index-name'))

600k行确实来自这样一个事实,即它在98k行上进行嵌套循环联接,并乘以7行。如果上面的索引不起作用,您可以尝试用
内部哈希连接iGroupes
替换
内部连接iGroupes

替换
iGroupes
上的3个索引(PK除外)都无法帮助此查询,因为您没有在where或JOIN子句中使用这些字段。除非其他查询需要这些索引,否则我将删除它们。他们只是给查询优化器更多的选择来测试(和拒绝)

主键
PK_igroups
上的索引应进行聚类。这将允许它进行索引查找(或书签查找)。如果由于其他原因无法对其进行聚集,请尝试按顺序在
IGroupID
缩写
上创建索引(或在现有PK索引中包含
缩写
列)

如果它仍然没有选择正确的索引,您可以使用提示,例如
WITH(index(0))
WITH(index('index-name'))



600k行确实来自这样一个事实,即它在98k行上进行嵌套循环联接,并乘以7行。如果上面的索引不起作用,您可以尝试用
内部哈希连接iGroupes
替换
内部连接iGroupes

来替换
内部连接iGroupes

您为什么不能将PK创建为集群?这可能会有帮助,而且是个好主意。@usr:我错把它删除了。谢谢现在显示聚集索引扫描。我想把它转换成seek。有什么办法吗?真奇怪。在执行计划中,ID列上似乎有一个简单的谓词。你能用CI发布新计划吗?你有更新的统计数据吗?您是否尝试将加入到IGroups的活动移出CTE?usr:感谢您的帮助。这是一个新的计划:你为什么不能将PK创建为集群?这可能会有帮助,而且是个好主意。@usr:我错把它删除了。谢谢现在显示聚集索引扫描。我想把它转换成seek。有什么办法吗?真奇怪。在执行计划中,ID列上似乎有一个简单的谓词。你能用CI发布新计划吗?你有更新的统计数据吗?您是否尝试将加入到IGroups的活动移出CTE?usr:感谢您的帮助。下面是新的计划:我尝试了这个解决方案,并将IGroupID设置为集群。现在显示聚集索引扫描。我想把它转换成seek。“有什么办法吗?”杰克,扫描不一定意味着比搜索更糟糕的事情。例如,如果查询所有表或索引数据,则扫描经常出现,而不是搜索。如果可以在键上搜索,我想不出CI扫描比CI搜索更可取的情况。@I-phone:我理解,但我只是查询缩写,它已经包含在NCI中了定义。@i-phone:我只担心这个问题,因为如果我不加入igroups(一个7行的小表),我的查询速度几乎降低了一半,因为你可以看到实际行数超过600K,我完全无法理解为什么会发生这种情况。这是一个包含7行的简单查找表,它使我的查询速度加倍:(.如果我不加入iGroup,我将在300毫秒内在100K记录表中返回结果,如果加入,我将在700毫秒内返回结果。对于查找表来说,这是一个相当大的差异:(我尝试了这个解决方案,并将IGroupID设置为聚集。现在它显示聚集索引扫描。我想将其转换为seek。有什么办法吗?@Jack,scan不一定意味着比seek更糟糕的事情。例如,如果查询所有表或索引数据,则扫描经常出现,而不是seek。我无法想出CI出现的情况如果可以在键上搜索,则扫描比CI搜索更可取。@i-phone:我理解,但我只是查询缩写,它已经在i中了