2011-08-19 44 views
6

我們目前有一種情況,一個表有效地具有幾個(10至15)布爾標誌(不可爲空的bit字段)。不幸的是,在邏輯層面上將其過分簡化是不太可能的,因爲任何布爾值的組合都是允許的。SQL Server中多位字段的索引

有問題的表是一個事務表,最終可能有數千萬行,並且插入和選擇性能都相當重要。儘管目前我們對數據的分佈還不太確定,但所有標誌的組合都應該提供相對良好的基數,即使它成爲SQL Server使用的「值得」索引。

典型的選擇查詢場景可能是僅基於3或4個標記來選擇記錄,例如, WHERE FLAG3=1 AND FLAG7=0 AND FLAG9=1。爲這些select查詢使用的所有標誌組合創建單獨的索引並不實際,因爲它們中會有很多。

鑑於這種情況,有效索引這些字段的建議方法是什麼?該表是新的,所以現在還沒有需要擔心的數據,並且我們在表的實際實施中具有相當大的靈活性。

有跡象表明,我們正在考慮在目前兩個主要選項:

  • 創建一個單一的指標,其中包括所有的位字段(這可能會包括1個或2個其他int領域它總是使用)。我擔心的是,鑑於僅包括幾個字段的典型用法,這種方法會跳過索引並求助於表掃描。我們稱之爲選項A(閱讀了一些回覆後,似乎這種方法效果不好,因爲索引中字段的順序會產生差異,從而無法在所有字段上有效地進行索引)。
  • 有效地做我認爲SQL Server在內部完成的任務,並使用二元運算符(將數字與1和2,4,8等組合在一起)將位字段編碼爲單個int字段。我的關注點是我們需要做一些計算來查詢這個編碼字段,這會再次跳過索引。維護和解決方案的複雜性也是一個問題。我們稱之爲選項B附加信息:參數對於這種方法是我們可以有一個相對簡單和短的索引,其中包括表和該字段中的一個或兩個其他字段。其他字段將縮小需要評估的記錄數量,並且由於編碼字段將包含我們所有的位字段,因此SQL Server將能夠使用從索引直接檢索的數據執行計算(即索引掃描)而不是表(即表格掃描)。

目前,我們非常傾向於選項B。爲了完整起見,這將在SQL Server 2008上運行。

任何意見將不勝感激。

編輯:拼寫,清晰度,查詢示例,關於的附加信息選項B

回答

3

雖然有可能的方式來解決對您現有的表架構你的索引的問題,我想這減少到正常化問題:

例如,我會強烈建議創造了一系列的新表:該位標誌的名稱

  1. 查找表。例如CREATE TABLE Flags (id int IDENTITY(1,1), Name varchar(256))(如果您想手動控制ID,例如2,4,8,16,32,64,128作爲二進制標記,則不必爲身份驗證種子列創建身份驗證列)。
  2. 創建新的link-表,其中包含原始數據表的id和新的鏈接表,例如CREATE TABLE DataFlags_Link (id int IDENTITY(1,1), MyFlagId int, DataId int)

然後,您可以在DataFlags_Link表創建索引,並寫這樣的查詢:

SELECT Data.* 
FROM Data 
INNER JOIN DataFlags_Link ON Data.id = DataFlags_Link.DataId 
WHERE DataFlags_Link.MyFlagId IN (4,7,2,8) 

至於性能,這就是好的DBA維護進來你要設置索引填充。 - 因素和填充適當的表,並運行定期索引碎片整理或按計劃重建索引。

性能和維護與數據庫齊頭並進。沒有其他人就沒有一個。

+1

有趣的是,感謝您的輸入。這種方法確實有一些缺點,例如記錄將被「複製」爲每個DataFlags_Link記錄(並且我不確定是否會導致重大性能下降)。另外,我們的查詢通常會檢查標誌是否爲0;即不存在於您的鏈接表中(對不起,如果我沒有在問題中指定這個)。我想,它最終會變得非常混亂。 –

+0

@Dnail:flag = 0檢查類似於'... WHERE NOT EXISTS(SELECT * FROM DataFlags_Link dfl WHERE dfl.DataId = Data.id)'並且應該使用索引。 –

6

單個BIT列通常不夠具有足夠的選擇性,甚至不能考慮用於索引。因此,單個BIT列上的索引實際上沒有意義 - 平均而言,您始終必須搜索表中大約一半的條目(50%選擇性),因此SQL Server查詢優化器將使用表掃描。

如果您在所有15個bit列上創建單個索引,那麼您不會遇到這個問題 - 因爲您有15個是/否選項,您的索引將變得非常有選擇性。

問題是:位列的序列很重要。如果您的SQL語句至少使用最左側的BIT列的1-n,那麼只會考慮您的索引

所以,如果你的指數是上

Col1,Col2,Col3,....,Col14,Col15 

那麼它可能被用於使用

  • Col1
  • Col1Col2
  • Col1Col2Col3 查詢。 ...

等等。但它不能用於指定Col6,Col9Col14的查詢。

因此,我並不認爲您的BIT列的索引真的有很大意義。

那些15 BIT列是您用於查詢的唯一列嗎?如果不是的話,我會嘗試將那些最常用的BIT列與其他列進行合併,例如對NameCol7什麼索引(然後你BIT列可以添加一些額外的選擇性另一個索引)

+1

感謝列順序信息(我實際上已經忘記了),我們將嘗試提出一個排序可能會工作。關於與其他欄目的結合;是的,我們總是會添加一列到應該立即過濾95%的表的索引。出於好奇,關於「50%選擇性」部分 - 如果這個數字偏向98%,而你正在查詢2%,會發生什麼? SQL Server是否足夠聰明以利用它?我確實意識到在這種情況下分區可能要優越得多。 –

+1

@Daniel B:是的,SQL Server的查詢優化器會保存您的數據及其分佈的統計信息。如果一個索引確實有足夠的選擇性來保證它的使用,那麼SQL Server的查詢優化器將使用它。所以,如果你有這樣一個「傾斜」的列 - 是的,該列的索引將有助於在你選擇1-2%的情況下 - 不在另一種情況下,但:-) –

+0

基數和選擇性不是當量;一個位域具有大約50%的基數(null是可能性),但是在選擇性上可能會有很大差異。有一些非常好的場景,在單比特字段上索引會證明是一個很大的好處。除了對位字段進行索引之外,SQL Server 2008+還可以對字段的一個值進行過濾,並創建一個只標識您感興趣的記錄的小索引。 – Suncat2000

1

雖然我認爲尼爾芬威克的答案可能是正確的,但我認爲真正的答案是嘗試不同的選項,看看哪一個足夠快。

選項1可能是最直接的解決方案,因此可能是最容易維護的 - 並且它可能足夠快。

我將建立一個原型數據庫,與「選項1」模式,並使用類似http://www.red-gate.com/products/sql-development/sql-data-generator/http://sourceforge.net/projects/dbmonster/創造兩倍的數據,你預計需要,然後構建您預計需要查詢。同意一個可接受的響應時間,並且如果超過了這些響應時間,則只考慮一個「更快」的模式(並且不能在硬件問題上拋出硬件)。

Neil的解決方案可能與「選項1」一樣明顯且易於維護 - 並且應該很容易進行索引。然而,我仍然通過創建一個原型架構並生成大量的測試數據來測試它...

+0

測試各種選項肯定會發生;我主要是保持這個問題的時間更長一些,以防有人可以提出另一個我們沒有想到的替代方案。 –

+0

出於好奇,在幾百萬條記錄進行了一些相對快速的測試之後,選項A和B似乎表現相對較好(都下降到一次索引搜索操作),而尼爾的一個速度慢了約40倍,並且超出範圍對於用戶可接受(20秒+)。該選項的執行計劃要複雜得多,包括散列連接等。很多數據也被物理複製(通過設計),導致表和索引比選項A和B大很多倍。看到任何方式以更有效的方式索引它。 –