我有一个包含5,651,744行的表,主键由6列(int x 3,smallint,varchar(39),varchar(2))组成。我希望使用此表和另一个共享此主键的表以及添加的另一列但具有37m行来提高性能。
在预期添加列以创建哈希键时,我进行了分析并发现了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()
考虑到我所覆盖的目标空间的相对较小量,这看起来是否太高(.33%)?如果碰撞很高,那么在连接中加入这个制造的密钥是否有利于每行额外4个字节的成本,因为你仍然必须加入常规列来处理偶尔的碰撞? / p>
答案 0 :(得分:7)
我没有看到添加校验和的位置会让你得到任何级别的collisons。即使1次碰撞也太多,因为它会导致您加入错误的数据。如果你不能保证加入正确的记录,那么如果它提高性能但是数据完整性混乱则毫无意义。这似乎是财务数据,因此您最好确保您的查询不会返回错误结果。如果发生任何冲突,您实际上最终可能会记入借方或记入错误的帐户。
如果你选择这条路线,Marc是正确的,如果可能的话,你应该预先计算(在数百万记录表中添加必须发生的计算不太可能提高我的经验)。可能如果您可以执行预先计算的列(并且您需要触发器以使其保持更新),那么您可能不需要连接到所有其他六列以确保没有冲突。那么可能你可能会有更好的表现。你所能做的只是测试你的理论。但请确保您没有任何碰撞。
您是否考虑使用代理键,然后在六个自然键字段上使用唯一索引?然后你可以加入代理键,这可能会提高性能。连接六列(一个varchar)而不是一个代理键是无效的。我从数据的大小中意识到,这可能比非生产系统更难重构,但实际上值得花时间来永久修复持久性性能问题。只有你可以说这是一个多么复杂的变化,以及将所有sps或查询更改为更好的连接有多难。但是,尝试可能是可行的。
答案 1 :(得分:6)
到目前为止,很多人都看到了CHECKSUM
因Microsoft's own admission而发生大量碰撞。它甚至比MD5
更糟糕,SHA1
有明显的有意义碰撞。
如果您希望获得哈希列,请考虑使用HASHBYTES
并指定SHA1
。
与MD5
或CHECKSUM
相比,CHECKSUM
碰撞的意义要小得多。因此,永远不应该使用HASHBYTES
来确定行是否唯一,而是快速检查两个值的保真度。因此,对于HASHBYTES
,您的碰撞率应为0%,除非您有重复的行(作为PK,绝不应该发生)。
请记住,{{1}}将截断大于8000字节的任何内容,但是你的PK比那些(所有连接的)少得多,所以你不应该有任何麻烦。
答案 2 :(得分:2)
如果你的校验和得到它的数据的0.33%,那么我认为它工作正常...特别是如果你将这个列与其他(索引)列结合使用。
当然,为了有效地作为索引,您可能希望在插入/更新数据时使用非聚集索引来计算和存储此值。
当然,对相关列的常规生成索引也可以做得更好或更好......
答案 3 :(得分:1)
如果您的查询是选择性的并且行表聚集索引很窄或不存在,那么行表中校验和上的非聚集索引应该提供良好的性能。
在将任何标准应用于头表后,它将使用校验和对非聚集索引执行索引查找。您仍然需要在连接中包含FK,但非索引连接条件将应用于索引后搜索,书签后查找。很有效率。
您希望针对索引搜索进行优化。校验和已经具有高度选择性。添加FK会增加索引大小和相应的I / O,除非包含足够的其他字段以完全避免书签查找,否则无济于事。
由于非聚集索引将包含聚类键或堆指针,因此您需要a)小型聚类键(例如,int标识列 - 4字节指针)或b)根本没有聚簇索引(8)字节指针)。
如果您的查询不是选择性的,或者行表聚集索引很大(整个表减去几列),那么我不知道校验和是否有帮助(更快的索引导航,也许?)。在任何情况下,您都希望将其设置为聚簇索引或覆盖索引,如果头表不首先聚集在校验和上,则会有很多排序。
如果您能负担得起存储和索引成本,可以采用一些覆盖索引 - 标题和详细信息。
答案 4 :(得分:1)
如果您的PRIMARY KEY
已群集,则您创建的每个索引都会包含此PRIMARY KEY
。
加入散列值将使用以下步骤:
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 Seek
和Filter
来确保哈希值匹配(并且它们总是会匹配)
摘要:只需加入PRIMARY KEY
。
使用辅助索引,您首先需要进行无用的HASH_KEY
搜索,然后仍然需要加入PRIMARY KEY
。