2009-06-22 73 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比这个(全部并置)要少很多,所以你不应该有任何麻烦。