2014-03-12 50 views
0

我正在創建一個篩選索引,以便WHERE篩選器包含完整的查詢條件。通過這樣的索引,似乎不需要關鍵列,儘管SQL需要我添加一列。例如,考慮表:哪些關鍵列用於包含WHERE子句的過濾索引?

CREATE TABLE Invoice 
(
    Id INT NOT NULL IDENTITY PRIMARY KEY, 
    Data VARCHAR(MAX) NOT NULL, 
    IsProcessed BIT NOT NULL DEFAULT 0, 
    IsInvalidated BIT NOT NULL DEFAULT 0 
) 

查詢在桌子上尋找新的發票的過程,即:

SELECT * 
FROM Invoice 
WHERE IsProcessed = 0 AND IsInvalidated = 0 

所以,我可以調整這些查詢與篩選的索引:

CREATE INDEX IX_Invoice_IsProcessed_IsInvalidated 
ON Invoice (IsProcessed) 
WHERE (IsProcessed = 0 AND IsInvalidated = 0) 
GO 

我的問題:IX_Invoice_IsProcessed_IsInvalidated的關鍵列應該是什麼?假定關鍵列未被使用。我的直覺導致我選擇一個很小的專欄,並保持指數結構相對平緩。我應該選擇表主鍵(Id)嗎?其中一個過濾器列,或兩者?

+1

您是否嘗試查看針對沒有索引的表的查詢的執行計劃,以查看建議的索引方式? – Tanner

+0

在測試了你的表並查看執行計劃之後,沒有建議任何索引,我懷疑這是因爲你沒有從位列索引中獲得很多好處。這個問題似乎支持了起來http://stackoverflow.com/questions/231125/should-i-index-a-bit-field-in-sql-server – Tanner

+0

@坦納:我已經看過執行計劃。查詢優化器在索引中的行數小於表中行總數的情況下(預期方案)選擇索引。我的問題是關於如何優化索引的效率(大小,I/O)。 –

回答

1

因爲你在該表上有一個聚集索引,所以放入該索引的關鍵字列中並不重要;意思Id是免費的。您唯一可以做的就是include索引的包含部分中的所有內容都可以在索引的葉級別實際擁有數據,以便將密鑰查找排除在表之外。或者,如果隊列很大,那麼可能還有一些其他列在關鍵部分中很有用。

現在,如果該表沒有主鍵,那麼您必須將include或指定爲鍵列才能用於連接或其他目的所需的所有列。否則,會在堆上進行RID查找,因爲在索引的葉級上,您將引用數據頁。

0

這個過濾後的指標覆蓋了多少百分比?如果它很小,則可能需要覆蓋整個表以處理索引中的「SELECT *」而不觸碰表。如果它是桌子的一大部分,儘管這不會是最佳的。然後我建議使用聚集索引或主鍵。我必須研究更多,因爲我現在忘記了哪一個是最優的,但如果它們是相同的,那麼應該設置。

+0

索引中的行數與表中的總行數相比較小,這就是我選擇過濾索引的原因。你能否詳細說明爲什麼要使用聚集索引/主鍵? 「最佳」是什麼意思? –

0

我建議你把它聲明如下

CREATE INDEX IX_Invoice_IsProcessed_IsInvalidated 
ON Invoice (Id) 
INCLUDE (Data) 
WHERE (IsProcessed = 0 AND IsInvalidated = 0) 

的include子句將意味着數據列的值將被存儲爲索引的一部分。

如果你沒有一個include子句然後

SELECT Id, Data 
FROM Invoice 
WHERE IsProcessed = 0 AND IsInvalidated = 0 

查詢計劃將包括兩個步驟

  • 使用索引來查找匹配的主鍵值的列表 標準
  • 從表中獲取與這些主鍵匹配的數據

另一方面,如果索引包含[數據]列,那麼它將正確覆蓋查詢,因爲不需要使用主鍵查找數據。

您沒有得到什麼都沒有

這樣做的缺點是,你將爲這些記錄存儲varchar(MAX)數據兩次,因此需要將更多的數據寫入數據庫,並且會使用更多的存儲,儘管這不是這樣如果你只是在討論一小部分數據,那麼問題就很大。

一如往常,您將更多的時間和精力放在仔細考慮之中,讓他們更快更容易。