2009-06-22 72 views
9

我已經得到的5651744行的表,用由6列的主鍵(INT×3,SMALLINT,VARCHAR(39),VARCHAR(2))。我期望通過此表和另一個表共享此主鍵以及添加一個附加列但具有37m行的另一個表來提高性能。校驗和()的碰撞2005

在添加一列創建哈希鍵的期待,我做了一個分析,發現18,733衝突。

SELECT SUM(CT) 
FROM (
     SELECT HASH_KEY 
       ,COUNT(*) AS CT 
     FROM (
       SELECT CHECKSUM(DATA_DT_ID, BANK_NUM, COST_CTR_NUM, 
           GL_ACCT_NUM, ACCT_NUM, APPN_CD) AS HASH_KEY 
       FROM CUST_ACCT_PRFTBLT 
       ) AS X 
     GROUP BY HASH_KEY 
     HAVING COUNT(*) > 1 
     ) AS Y 

SELECT COUNT(*) 
FROM CUST_ACCT_PRFTBLT 

這是大約兩倍的壞與給定的目標空間,我需要覆蓋的較小的相對量BINARY_CHECKSUM()

這看起來太高(0.33%)?如果碰撞率很高,考慮到您還需要加入常規列以處理偶爾發生的碰撞,那麼在聯接中首先加入這個製造的密鑰會使每行多餘的4字節的代價有什麼好處?

+0

您一次加入多少條記錄?細節表是否有聚集索引?有多寬?如果聚集索引很寬(即它包含所有FK),您可以放棄它還是將其替換爲標識列? – 2009-06-24 03:18:02

+0

爲什麼這是你的問題?你需要完成什麼? – 2009-07-06 13:27:30

+0

問題是,我有200m行導出的統計信息從37m行的統計信息中產生,並且執行計算的PIVOT必須在一個非常大的密鑰上進行轉換,這導致了所有37m行到tempdb的令人討厭的急切後臺處理。 – 2009-07-06 14:33:29

回答

7

我沒有看到添加的校驗將讓你與collisons該級別的任何東西。即使1次碰撞太多,因爲它會導致您加入錯誤的數據。如果您不能保證加入正確的記錄,那麼提高性能但會破壞數據完整性毫無意義。這似乎是財務數據,所以你最好確定你的查詢不會返回不好的結果。如果發生任何碰撞,您實際上可能會最終扣除或記入錯誤的帳戶。

如果你確實走這條路線,馬克是正確的,你應該在所有可能的預計算(添加一個計算必須發生在每百萬記錄表中的記錄不可能改善我的經驗)。可能的話,如果您可以執行預計算列(並且您需要觸發器來保持它的更新),那麼您可能不需要連接到其他所有六列以確保沒有衝突。那麼你可能會失去表現。你所能做的就是測試你的理論。但要確保你沒有任何碰撞。

你有沒有考慮過使用代理鍵,然後在六個自然鍵字段上使用唯一索引?然後你可以加入代理鍵,並且可能會提高性能。在六列(一個varchar)而不是一個代理鍵上加入效率不高。我從數據的大小中認識到,這可能比在非生產系統中重構更難,但真正值得暫時解決持久性能問題的停機時間可能是值得的。只有你可以說這將是多麼複雜的變化,以及將所有sps或查詢更改爲更好的連接將會多麼困難。但是,嘗試可能是可行的。

+0

我將不得不加入surrgate和所有PK列。代理將需要成爲索引中的第一列(優化器希望可以選擇),但所有列都必須加入。在此MSDN文檔中有一個示例(只是一個查找,而不是聯接):http://msdn.microsoft.com/en-us/library/ms189788(SQL.90).aspx – 2009-06-22 20:56:36

2

如果校驗得到它歸結爲數據的0.33%,那麼我認爲,這是工作的罰款......特別是如果你結合使用此列與其他(索引)列。

當然是有效的,你可能想在插入時/更新數據,與非聚集索引計算和存儲該值的索引。

當然,在對有關列常規跨越指數可能會做一樣好或更好...

+0

是的,我打算使用持久計算列。 – 2009-06-22 20:10:46

1

如果你的查詢都是選擇性的,行表聚集索引較窄,或者不存在,則在該行表校驗一個非聚集索引應提供良好的性能。

施加任何標準之後存在於標題表,它將使用校驗和來執行對非聚集索引索引查找。您仍然需要在連接中包含FK,但非校驗和連接條件將應用於索引後查找和後期書籤查找。非常有效。

您希望針對索引查找進行優化。校驗和已經非常具有選擇性。添加FK會增加索引大小和相應的I/O,並且除非包含足夠的其他字段以避免書籤查找完全無效。由於非聚簇索引將包含聚簇鍵或堆指針,因此您希望a)一個小的聚簇鍵(例如,一個int標識列 - 4個字節的指針)或b)根本沒有聚簇索引8字節指針)。

如果您的查詢沒有選擇性,或者行表聚簇索引很大(整個表減少幾列),那麼我不知道校驗和是否會有幫助(可能更快的索引導航?)。在任何情況下,您都希望將其設置爲聚簇索引或覆蓋索引,並且如果頭表未首先聚集在校驗和上,則會有很多排序。

如果你能負擔得起存儲和索引成本,一些覆蓋索引 - 標題和詳細信息 - 可能是要走的路。

1

如果您的PRIMARY KEY已集羣,則您創建的每個索引都將包含此PRIMARY KEY

入世對散列值將使用以下步驟:

  1. 找到索引鍵的哈希值
    • 索引數據找到PRIMARY KEY
    • 使用Clustered Index Seek定位PRIMARY KEY行中的表

加入PRIMARY KEY將只使用步驟3

SQL Server,然而,是足夠聰明,考慮到這一點,如果你能加入這樣的:

SELECT * 
FROM main_table mt 
JOIN CUST_ACCT_PRFTBLT cap 
ON  cap.HASH_KEY = mt.HASH_KEY 
     AND cap.DATA_DT_ID = mt.DATA_DT_ID 
     AND … 
WHERE mt.some_col = @filter_value 

,它只是將不會使用索引上HASH_KEY,相反,它會使用一個單一的Clustered Index SeekFilter以確保散列值匹配(並且它們總是會)。

摘要:剛加入PRIMARY KEY

使用輔助索引,您首先需要做一個無用的HASH_KEY搜索,然後仍然需要加入PRIMARY KEY

6

我到目前爲止看到的很多人都在說,CHECKSUM有很多碰撞,由Microsoft's own admission。它甚至比MD5還要糟糕,因爲它有相當多的有意義的碰撞。

如果您正在尋找哈希列,請考慮使用HASHBYTES並指定SHA1。與MD5CHECKSUM相比, SHA1具有更少的有意義的碰撞。因此,決不應該使用CHECKSUM來確定一行是否是唯一的,而是對兩個值的保真度進行快速檢查。因此,除非你有重複的行(這是一個PK,它永遠不會發生),否則碰撞率應該爲0%HASHBYTES

請記住,HASHBYTES會截斷大於8000字節的任何內容,但是你的PK比這個(全部並置)要少很多,所以你不應該有任何麻煩。