2012-12-07 17 views
1

SQL小提琴:http://sqlfiddle.com/#!3/23cf8獲取RID查找而不是表掃描?

在此查詢,當我有一個ID爲In條款,然後還要選擇其他列中,在首先進行評估,然後將詳細列和其他列通過拉入RID查找:

--In production and in SQL Fiddle, Details is grabbed via a RID Lookup after the In clause is evaluated 
    SELECT [Id] 
     ,[ForeignId]  
    ,Details  
     --Generate a numbering(starting at 1) 
     --,Row_Number() Over(Partition By ForeignId Order By Id Desc) as ContactNumber --Desc because older posts should be numbered last 
    FROM SupportContacts 
    Where foreignId In (1,2,3,5) 

使用此查詢,詳細信息正通過表掃描進入。

With NumberedContacts AS 
(
    SELECT [Id] 
     ,[ForeignId] 
     --Generate a numbering(starting at 1) 
     ,Row_Number() Over(Partition By ForeignId Order By Id Desc) as ContactNumber --Desc because older posts should be numbered last 
    FROM SupportContacts 
    Where ForeignId In (1,2,3,5) 
) 
Select nc.[Id] 
     ,nc.[ForeignId] 
     ,sc.[Details] 
From NumberedContacts nc 
Inner Join SupportContacts sc on nc.Id = sc.Id 
Where nc.ContactNumber <= 2 --Only grab the last 2 contacts per ForeignId 
; 

在SqlFiddle,第二個查詢實際生產中得到了RID查找,而用一百萬條記錄它會產生一個表掃描(在IN條款消除了行的99%)

否則查詢計劃在SQL小提琴顯示的是相同的,唯一的區別是,對於第二個查詢在SQL小提琴的RID查找,是表掃描在生產:(

  1. 我想明白,將導致此行爲的可能性?哪一種s的東西你會看看幫助確定它的原因在這裏使用表掃描?

  2. 我該如何影響它在那裏使用RID查找?

通過觀察在實際執行計劃經營成本,我相信我能拿到第二個查詢非常接近在性能上的第一個查詢,如果我能得到它使用一個RID查找。如果我不選擇Detail列,那麼兩個查詢的性能在生產中都非常接近。只有在添加其他列(如Detail)之後,第二個查詢的性能纔會顯着下降。當我把它放在SQL小提琴中,看到執行計劃使用RID查找時,我很驚訝,但有點困惑...

它沒有聚集索引,因爲在測試時使用不同的聚簇索引,這個和其他查詢的性能較差。那是在我開始添加像Details之類的其他列之前,我可以嘗試更多,但是想要在隨機索引在黑暗中開始拍攝之前瞭解現在正在發生的事情。

回答

2

如果您要將主索引更改爲包含Details列,該怎麼辦?

如果你使用:

CREATE NONCLUSTERED INDEX [IX_SupportContacts_ForeignIdAsc_IdDesc] 
ON SupportContacts ([ForeignId] ASC, [Id] DESC) 
INCLUDE (Details); 

然後將既不需要RID查找,也不是表掃描,因爲你的查詢可以只從指數本身....

+0

也許你的意思是這個CREATE非聚集索引[IX_SupportContacts__Id] ON SupportContacts ([ID] ASC)包括:([詳情]); –

+0

我認爲該索引,但想知道如果使索引的這樣一個大的字段部分會膨脹索引很多,並可能對該字段的插入/更新有很大的影響?不要試圖變得困難,只是對你的觀點感興趣。 – AaronLS

+1

@AaronLS:你沒有詳細提及這些列有多大 - 而INCLUDE的美妙之處在於:這些值僅在索引的葉級別存儲**,但不包括**, *在葉級以上的索引結構中!這是一種非常高效且非常漂亮的獲得性能的方式 - 避免RID或密鑰查找可以提高性能** ** –

1

查詢計劃中的差異將取決於存在的索引的類型以及不同環境中這些表的數據的統計信息。

優化器使用統計信息(主要是數據頻率的直方圖)和可用的索引來決定哪個執行計劃最快。

因此,例如,您已經注意到包含'詳細信息'列時性能會降低。這是一個幾乎可以肯定的跡象,即「詳細信息」列不是索引的一部分,或者如果它是索引的一部分,那麼該列中的數據大部分是唯一的,這樣索引訪問將是等效的(或幾乎相同)到表掃描。

通常,當這種情況出現時,優化器將選擇對索引訪問進行表掃描,因爲它可以利用塊讀取等功能來訪問表記錄,這比讀取索引的碎片更快。

爲了影響優化程序將要選擇的路徑,您需要查看可能添加/修改的索引,以便使索引訪問更加高效,但這應該小心謹慎,因爲它可能會產生不利影響其他查詢以及可能降級的插入性能。

您可以幫助優化器的其他重要活動是確保表格統計信息保持最新狀態並刷新爲適合表格數據中頻率分佈變化率的頻率

1

得到滿足。如果這是真的如果使用相關索引+ RID執行查詢,那麼99%的行將被省略,那麼生產環境中最可能出現的問題是您的統計信息已過期,並且優化程序不會意識到(1,2 ,3,5)將結果集限制爲總數據的1%。

這裏有一個很好的鏈接,發現更多關於皮納爾戴夫統計:http://blog.sqlauthority.com/2010/01/25/sql-server-find-statistics-update-date-update-statistics/

爲強制優化器按照正確的路徑不更新的統計數據,你可以使用表提示 - 如果你知道索引你的計劃應該是使用包含ID和ForeignID列然後堅持,在您的查詢的提示和力量SQL優化器使用索引:

http://msdn.microsoft.com/en-us/library/ms187373.aspx

僅供參考,如果你想從你的第二個最佳性能查詢,使用這個索引並避免t他頭痛您遇到乾脆:

create index ix1 on SupportContacts(ForeignID, Id DESC) include (Details); 
相關問題