Sql-Server

更新性能:聚集索引與覆蓋索引

  • October 9, 2017

我有一個簡單的 3 列表,其中包含大約 5000 萬行。該表每秒大約進行 5,000 次插入/更新,並且每秒可能對該表執行 20 次查詢。該表如下所示:

Controller: Int
ExecutionTime: DateTime
Result: Int

為了最大限度地提高查詢效率,我需要兩個索引。(結果包括執行時間)和(控制器,執行時間)。這兩個索引完全覆蓋了我的查詢——所有資訊都直接從索引中提供,不需要表查找。

我選擇了非聚集索引,因為我擔心使用具有如此多更新的聚集索引會降低性能。但我突然想到,由於我完全覆蓋了查詢,這可能不是一個有效的問題——也許我的覆蓋非聚集索引需要與聚集索引相同的維護量。

所以我的問題是: 在具有大量插入/更新的表中,覆蓋的非聚集索引通常會比聚集索引具有更低的 UPDATE 性能影響嗎?

感謝您的時間和幫助!

在幕後,聚集索引和非聚集索引是相同的。聚集索引只是具有保證包含所有列的附加屬性。因此,數據不需要在其他地方維護。因此,從更新成本的角度來看,包含所有列的聚集索引和非聚集索引實際上是相同的。

但是,如果每個索引都包含在更新期間更改的列,則需要維護它。這意味著,您擁有的索引越多,更新的成本就越高。

所以在你的情況下,我會盡量減少索引的數量。這將有助於更新性能,而不是擔心特定索引是否更好地聚集或覆蓋。

話雖如此,您的更新仍然需要盡快找到要更新的行。因為你有兩個數量級的更新然後選擇,所以在設計索引策略時應該首先考慮更新。處理完它們後,請考慮為讀取查詢提供最少數量的適當索引。

在您的情況下,您的非聚集索引都包括表中除一列之外的所有列,並且都是完整記錄大小的 3/4(假設您使用的是 8 字節 DATETIME)。基於此,每個非聚集索引的 IO 成本應該是聚集索引的 IO 成本(如果有的話)的 75% 左右。

現在,因為您沒有聚集索引,所以您有一個堆,顯然需要像索引一樣維護它。

假設插入整行(到堆或聚集索引)的成本是 100%,讓我們考慮在插入期間必鬚髮生的事情:

1) insert new row into heap (cost=100%)
2) insert new row into non-clustered index #1 (cost=75%)
3) insert new row into non-clustered index #2 (cost=75%)

在更新期間(假設您只更新結果):

1) Update the row in the heap  (cost=100%)
2) Update non-clustered index #1 (cost=75%)

1 次插入、1 次更新的總成本 = 425%

讓我們看看如果將 (Controller, ExecutionTime) 集群化會發生什麼。

對於插入:

1) insert into the clustered index  (cost=100%)
2) insert into the non-clustered index (Result Includes Execution Time) (cost=75%)

對於更新(假設您只更新結果,希望這是一個正確的假設):

1) update the clustered index   (cost=100%)
2) update the non-clustered index (Result Includes Execution Time) (cost=75%)

1 次插入、1 次更新的總成本 = 350%

因此,就寫入而言,讓您的 (Controller, ExecutionTime) 集群擺脫堆是有意義的。

我還應該提到堆因碎片而臭名昭著(在您的情況下這可能不是問題,因為您沒有提到刪除並且所有列都是固定大小的),並且通常不建議用於 OLTP 流量。

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