Sql-Server

SQL Server:涵蓋包括所有列的索引?

  • March 13, 2019

我們的團隊繼承了一個應用程序和相關的數據庫。以前的開發人員似乎強制執行了一個規則,即每個表上的每個索引都有一個 INCLUDE 子句,以始終添加不屬於鍵的每一列。這些表平均有 2 到 5 個索引或唯一約束以及外鍵。

無論在數據庫中拋出什麼查詢,目的似乎都是為了提高 SELECT 性能,因為訪問是通過預設情況下(但不總是)檢索所有列的 ORM。我們預計這樣做的副作用是增加儲存需求(可能顯著增加)和額外的 INSERT/UPDATE/DELETE 成本時間。

問題是,這是一個明智的策略嗎?我們的團隊有使用 SQL Server 的歷史,但沒有成員會認為自己是其內部行為方面的專家(儘管有人提出問題,如果這種策略是最優的,那麼它現在不是預設的嗎?)。我們應該期待哪些其他副作用(數據庫伺服器 CPU/記憶體/TempDB 使用等),或者我們上面的一些假設不正確?

此外,該應用程序可以安裝到本地 SQL Server(自 2012 年以來的版本)和 Azure SQL 中——我們是否應該為兩者之間的任何差異或 Azure 上的其他副作用做好準備,因此方法?

我之前已經在特定索引上完成了此操作,以幫助經常執行的繁重查詢。他們所做的實際上是創建多個聚集索引:當使用這些索引中的任何一個來查找行時,不需要額外的工作來查找真正聚集索引中的其餘數據(或者如果沒有真正的聚集索引,則在堆中查找) .

這是一個明智的策略嗎?

對於需要支持某些查詢模式的某些索引,當然可以。

但是要對所有索引執行此操作,我當然會說不。

在實際上不需要的地方做會浪費空間,並且會顯著減慢插入/更新速度。它也可能會減慢盡可能多的讀取查詢,因為每個索引頁面保存的記錄較少,因此任何需要引用索引塊進行過濾但不使用所有其他列的查詢都必須訪問更多頁面。這將使您的數據庫更加佔用記憶體:這些頁面將需要載入到緩衝池中,如果記憶體不足,可能會彈出其他有用的頁面。如果在這些索引上使用壓縮來嘗試減輕對儲存和記憶體需求的影響,那麼它將向 CPU 推送額外的負載。

因為訪問是通過預設情況下(但不總是)檢索所有列的 ORM

這是一種常見的模式,對 ORM(或只是簡單的 ORM)的使用優化不佳,在這些情況下,我看到 SQL Server 的索引顧問(和類似的第 3 方工具)建議使用許多INCLUDEd 列的索引,所以我同意你的建議這就是以這種方式創建索引的原因。

但是,雖然它可能會使所有此類查詢稍快一些,其中一些查詢速度明顯更快,但我懷疑在許多情況下,任何好處都是如此之小,以至於不值得您的公共工作集所需的額外記憶體佔用、磁碟空間和磁碟和記憶體之間的 IO。

還要記住,ORM 可能不會選擇查詢涉及的所有表的所有列,因此這種好處可能只適用於目前請求的主要目標,並且當使用其他對象進行過濾時,較大的索引可能會懲罰查詢但不返回數據(SELECT * FROM table1 WHERE id IN (SELECT someID FROM table2 WHERE someColumn='DesiredValue')也許)。

使用的多餘空間的另一個考慮因素是,特別是在數據很大的情況下,它會對您的備份策略產生影響:這些備份的儲存和傳輸成本、潛在的恢復時間等等。

我們是否應該為兩者之間的任何差異做好準備

$$ on-prem & AzureSQL $$

一般來說,我認為這裡的考慮因素在每種情況下都是相同的,儘管大型索引造成的任何額外記憶體/IO 成本可能在 Azure 中更直接可見,您可以在其中調整服務層,因此更容易而不是調整基礎設施成本擁有一套相對固定的硬體資源。如果使用標準/高級層而不是基於 vcore 的定價,那麼您將受到標準中 IO 成本的更多影響,因為高級包含每個 DTU 顯著更多的 IO。如果您在 Azure 中使用多區域備份或冗餘或其他非本地功能,則可能會產生與不必要的寬索引佔用的額外空間相關的頻寬成本。

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