使用hashbytes比不使用hashbytes比较SQL Server表

时间:2012-10-08 20:01:26

标签: sql sql-server

我正在使用SQL Server 2012 LocalDB。

客户希望我比较nvarchar(max)个值的200(!)列中的每个表(相信与否)。没有索引,也没有唯一的密钥。

我用google搜索(http://weblogs.sqlteam.com/jeffs/archive/2004/11/10/2737.aspx)并且方法有效。但是在union all / group by表达式中使用200列有点慢。

查询看起来像这样

SELECT 
    MIN(TableName) as TableName , header1, header2, header3, header....
INTO RESULTS  
FROM 
    (SELECT 
        'table1' as TableName, table1.header1, table1.header2, table1.header3, table1.header...
     FROM table1 

     UNION ALL 

     SELECT 
         'table2' as TableName , table2.header1, table2.header2, table2.header3, table2.header...
    ) tmp 
GROUP BY 
    header1, header2, header3, header...
HAVING 
    COUNT(*) = 1

Excecution Plan of first query

我的想法是计算任何行的hashbyte值,如此处所述(http://www.bidn.com/blogs/TomLannen/bidn-blog/2265/using-hashbytes-to-compare-columns)并将其保存在一个额外的列中(在这种情况下还有一个不受伤害:-))。 hashbytes本身的计算速度非常快,但是当我在我的union all / group by / having子句中仅使用hashbyte值运行我的查询时,查询速度要慢得多。在第一种情况下,它运行大约15分钟而不是大约25秒!

第二个查询看起来像这样(compareHash是插入的hashbyte列):

SELECT 
    MIN(TableName) as TableName, compareHash 
INTO RESULTS  
FROM 
   (SELECT 
       'table1' as TableName , compareHash 
    FROM table1 

    UNION ALL 

    SELECT 
       'table2' as TableName , compareHash 
    FROM table2) tmp 
GROUP BY 
    compareHash 
HAVING 
    COUNT(*) = 1

Execution Plan for second query 我原以为是完全相同的。任何人都可以考虑这种行为的原因吗?

祝你好运 塞巴斯蒂安

1 个答案:

答案 0 :(得分:0)

如果查看查询计划,您会注意到第二个查询返回的行数明显减少(根据箭头的粗细来判断)。

这让我想知道您是否正确填充了compareHash列。即如果所有200列都正确地包含在哈希中。

如果有的话,我希望第二个查询返回 more 行,因为散列字符数据会强制比较区分大小写。 sql server中的默认排序规则将对您对varchar值的第一个查询执行不区分大小写的比较。

虽然这与正确性有关,但您通常希望比较在比较性能时产生相同答案的方法。


除了正确性之外,另一个观察是在第一个查询中,数据被排序,然后应用流聚合。在第二个查询中,构建了一个哈希表,第二个表用于探测哈希表。您可以尝试通过在查询末尾添加OPTION (ORDER GROUP)来强制排序第二个查询中的流聚合计划,看看是否会改变执行时间,但我怀疑它会改进它。

我的猜测是原始varchar数据有一些sql server在第一个查询中利用的自然顺序。

如果您愿意在compareHash列上创建索引,那么您可能会在第二个查询中看到显着的性能提升,因为它将使用合并连接。