Sql-Server

如果索引不是最具選擇性的,如何提高性能?

  • March 3, 2014

根據建議索引必須是最有選擇性的以提高性能。 作為一般準則,我們應該在經常被查詢少於表的 15% 行的表上創建索引。 索引列/列中不同值的數量與表中記錄數的比率表示一個索引。

具有良好選擇性的範例:

一個有 100K 記錄的表,其中一個索引列有 88K 個不同的值,那麼這個索引的選擇性是 88K / 100K = 0.88。

現在我來重點了。我有一張有180K記錄的表。搜尋條件中經常使用的欄位是:

  1. 搜尋Name使用者的使用記錄。 Field Type :-> Not null , nvarchar(32). 唯一記錄為 627
  2. 使用 搜尋記錄Active_dateField Type :-> DateTime ,Null. 唯一記錄為 85627
  3. 使用 搜尋記錄 Current_state Field Type :-> Not Null , nvarchar(32)唯一記錄只有 2 條“待處理”和“已關閉”。

目前,上述所有欄位均已編入索引。就選擇性而言,情況(1)和(3)並不是最具選擇性的。為了提高性能,我應該如何處理它們?

沒有太多細節,我不能推薦太多。

確實讓我感到震驚的一件事是,您很可能可以通過對其進行規範化來提高桌面性能!您列出的列中存在如此多的重複值(如此少的唯一值)表明表中的許多其他值也可能未標準化。我建議使Name列 a int(或什smallint至)具有Names表的外鍵,而Current_statebit(或 a tinyint)具有WhateverStates表的外鍵。當然,您必須更改數據訪問程式碼來處理這種間接性,但這只不過是關係數據庫開發人員一直必須做的基本工作。

規範化將減少每行的字節數,增加每頁的行數,減少為滿足任何特定查詢而必須讀取的頁數,從而全面提高性能!現在給定的列每個可能需要接近 34 個字節。在我建議的更改之後,這些列將只需要 11 個字節。當然,我還沒有看過你的整張桌子——你的行可能太大了,沒關係。

聚集索引中有哪些列和數據類型(如果有)?這會從根本上影響非聚集索引的大小,再次以我描述的方式(每頁的行數)影響性能。

當您基於非選擇性列(例如 )進行查詢時Current_state,總是或幾乎總是包括哪些其他列?如果索引還包含一個更具選擇性的列(或者與選擇性較低的列結合起來具有更高的選擇性),那麼在索引中擁有一個非選擇性列可能是可以的。另一方面,如果您通常經常查詢基於單列的行Current_state = 'Pending',那麼您可以添加過濾索引:

CREATE INDEX IX_YourTable_Pending ON dbo.YourTable (ClusteredColumnsInOrder)
WHERE Current_State = 'Pending'; --SQL 2008 and up only

即使您還包含其他列,此技術也可以為您提供幫助:您可能希望將它們放在索引中而不是ClusteredColumnsInOrder我建議的列中(這只是不將任何其他列放入非聚集索引中的一種棘手方法,因為 – 記住,現在——非聚集索引總是隱含包含聚集索引的所有列)。或者,如果您只提取很少的其他列,則可以通過添加使非聚集索引覆蓋INCLUDE (AdditionalColumn1, AdditionalColumn2)查詢,這樣查詢引擎就不必返回聚集索引來滿足查詢。

您沒有提供太多資訊,例如完整的表架構、範例數據和範例查詢,如果沒有這些資訊,就很難為您提供非常具體的建議。

不過,我可以說的一件事是,不分青紅皂白地將索引放在桌面上可能不會改善很多事情,實際上可能會損害系統的整體性能。

如果我在這裡給您的提示似乎沒有太大幫助,那麼我建議您返回一些我提到的其他資訊,以便我們可以更好地為您提供幫助。

如果您不知道他們將搜尋哪些欄位,則不應為所有欄位創建索引。他們仍然可以搜尋它們。

沒有什麼說查詢不會很好地執行。該準則的原因是,這通常是 SQL Server 在查看統計資訊以確定它是否應該使用您創建的索引時所做的事情。

如果您總是查詢這些欄位,最好對附加欄位(名稱、Current_State)進行覆蓋索引,這樣 SQL Server 就不必再查找與日期匹配的記錄,它已經有了附加數據需要。(有名字,這可能不是一個好主意)

最終,您應該執行一些查詢(使用各種索引)並查看統計資訊,看看哪個根據您的條件執行得最好。

引用自:https://dba.stackexchange.com/questions/49580