簡體   English   中英

三列的復合索引

[英]Composite index on three columns

我們得到了93M行的映射表,其中保存了三個表和對應的三個表的映射信息。 我們在從映射表訪問數據時面臨性能問題。

表名 PK信息 行數
賣方 SellerId 主鍵 3000 行
店鋪 StoreId 主鍵 20000 行
產品 ProductId 主鍵 200k 行
賣家商店產品映射 SellerId,ProductId,StoreId 復合非聚集索引。 此表中還有一個代理鍵:SellerStoreProductMappingId,用作集群的主鍵 93M 行

我們的查詢可以訪問以下三種組合中的任何一種:93M 行表中的Seller, Product, Store

我的實際查詢是這樣的:

SELECT < many columns from four tables>
FROM SellerStoreProductMapping
INNER JOIN Store
INNER JOIN Seller
INNER JOIN Product ...
WHERE SellerId = 123

但是,正在發生的是非聚集索引:SellerId、ProductId、StoreId 在我們的查詢中很少使用,即使我們對 SellerId 進行了過濾。 它用於 storeId 的索引掃描。

我們的疑問是,對於這三列組合,

  1. 我們應該為單獨的非聚集索引(3 個索引)使用 go 嗎?
  2. 我們應該為兩列非聚集復合索引(4 個索引)使用 go 嗎?
  3. 我們應該 go 用於三列復合非聚集索引(9 個索引)。 代替 9,我們將限制在特定的使用場景。 ?

注意:我們無法創建聚集列存儲索引,因為我們將 ROWVERSION 數據類型作為映射表中的數據類型之一。

這可能不是答案(但我不允許發表評論),還有一點需要考慮:綜合索引中的索引順序。

如果您在 SellerStoreProductMapping 表中按以下順序定義復合索引:SellerId,StoreId,ProductId,那么它只能有效地用於過濾 SellerID OR for (SellerId and StoreId) OR for (SellerId and StoreId and ProductId) 的查詢

如果您在查詢中將三列(7 種可能性)的所有可能組合作為過濾器,那么您可能需要定義至少三個單獨的索引。

可以在此處找到對此的一些參考: https://use-the-index-luke.com/sql/where-clause/the-equals-operator/concatenated-keys

如果該索引涵蓋了查詢中的所有信息並且謂詞是可搜索的,那么您的索引將被系統地使用。

例如,讓我們看看這些查詢:

--1
SELECT *
FROM   SellerStoreProductMapping
WHERE  Seller = 1 AND Product = 2 AND Store = 1
-- 2
SELECT Seller, Product, Store
FROM   SellerStoreProductMapping
WHERE  Seller = 1 AND Product = 2 AND Store = 1
-- 3
SELECT anyOtherColumns
FROM   SellerStoreProductMapping
WHERE  Seller = 1 AND Product = 2 AND Store = 1
-- 4
SELECT Seller, Product, Store
FROM   SellerStoreProductMapping
WHERE  Seller = 1 AND Product = 2 AND Store = 1
ORDER  BY anyOtherColumns

只有查詢 2 會系統地使用索引。 所有其他查詢(1、3、4)沒有查詢中使用的所有列,在索引鍵中......所以他們必須使用雙重讀取:

  • 首先讀取(在索引中查找)以查找在謂詞下合格的候選行
  • 第二次讀表找到索引沒有的列

兩次讀取的成本與掃描表等其他策略的成本相比。 如果掃描成本較低,則不會使用索引...

關於索引中的列順序要記住的一些經驗法則:

  • WHERE = predicate 中引用的任何列以及唯一連接中引用的任何列放在索引鍵的第一個位置(連接從另一個表返回單行)
  • 然后是任何范圍謂詞,例如> <= < <> BETWEEN
  • 然后其他連接列
  • 然后任何排序列
  • 不要忘記為您選擇的任何其他列添加INCLUDE
  • 如果您可以在同一級別的兩列之間進行選擇,請首先選擇具有最高選擇性的列。

因此,如果您的查詢是針對單個賣家和商店,但有很多產品,那么您需要一個索引(Seller, Store, Product)(Store, Seller, Product) ,具體取決於列的選擇性。

進一步說明:

  • 如果您選擇的列未包含在索引中,編譯器可能會決定執行聚集索引掃描,因為額外的鍵查找成本可能不值得。

  • 只有當編譯器可以計算出連接在唯一的行上時,編譯器才能檢測到唯一的連接表。 因此,請始終確保使用PRIMARY/UNIQUE KEY或使用唯一索引聲明唯一列。

  • 在您的情況下,您的連接表有一個額外的代理主鍵,我認為這是不必要的,因為其他三個列唯一地定義了該行。 即使你需要它,你也不必聚集在它上面。 您可以使用與 PK 完全分開的聚集索引(它充當包含所有列的索引)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM