在很多系统设计的时候包括OS,SQL Server很多方面都用到了HASH大大提高了系统的性能,其实我们也可以利用SQL Server的HASH函数实现相同的效果。 比如对长String的Text创建HASH索引快速提高查询能力,可以用来比较表数据差异。
下面有两个例子:
1.用于比较两表的数据异同.
例如找出在T1有,T表没有的记录。
SELECT*
FROMT1
WHERECHECKSUM(*)
NOTIN(SELECTCHECKSUM(*)FROMT)
2.用于创建计算列索引
下列示例显示使用CHECKSUM 生成哈希索引。通过将计算校验和列添加到索引的表中,然后对校验和列生成索引来生成哈希索引。
– Create a checksum index.
SET ARITHABORTON;
USEAdventureWorks;
GO
ALTER TABLE Production.Product
ADD cs_Pname ASCHECKSUM(Name);
GO
CREATE INDEX Pname_indexONProduction.Product(cs_Pname);
GO
校验和索引可用作哈希索引,尤其是当要索引的列为较长的字符列时可以提高索引速度。校验和索引可用于等价搜索。
/*Use the index in a SELECT query. Add a second search
condition tocatch stray cases where checksums match,
but the valuesare not the same.*/
SELECT *
FROM Production.Product
WHERE CHECKSUM(N’Bearing Ball’)= cs_Pname
AND Name = N’Bearing Ball’;
GO
对计算列创建索引将具体化为校验和列,对ProductName 值所做的任何更改都将传播到校验和列。也可以直接对索引的列生成索引。然而,如果键值较长,则很可能不执行校验和索引甚至常规索引。
但是使用 CHECKSUM()也是有风险的,有可能两个不同的值会产生同样的HASH值,这样比对的数据j就会错误,虽然这样的情况非常少。
比如下面的两个数据不同,但是HASH的结果是相同的。
DECLARE@guid1UNIQUEIDENTIFIER,@guid2UNIQUEIDENTIFIER
SELECT@guid1=’3DB7D309-A8F4-47C4-BA90-0CB458B44CB0′, @guid2=‘EFE7F2C5-19F9-42B9-9C16-21BED41E882B’
SELECT chksum_guid1=CHECKSUM(@guid1),chksum_guid2=CHECKSUM(@guid2)
针对上面提到的问题有些专家给出了下面的解决办法:可以使用CHECKSUM两次,一次正向一次做反向HASH然后把两次的结构加在一起,这样出现碰撞的机会就很少了。
DECLARE@guid1UNIQUEIDENTIFIER,@guid2UNIQUEIDENTIFIER
SELECT@guid1=’3DB7D309-A8F4-47C4-BA90-0CB458B44CB0′, @guid2=‘EFE7F2C5-19F9-42B9-9C16-21BED41E882B’
SELECT chksum_guid1 = CONVERT(BIGINT,CONVERT(BINARY(4),CHECKSUM(REVERSE(@guid1)))+CONVERT(BINARY(4),CHECKSUM(@guid1)))
, chksum_guid2 = CONVERT(BIGINT,CONVERT(BINARY(4),CHECKSUM(REVERSE(@guid2)))+CONVERT(BINARY(4),CHECKSUM(@guid2)))
经过优化之后我们可以看到HASH的结构已经不一样了,这样就避免的HASH值的碰撞。