我正在使用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
我的想法是计算任何行的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
我原以为是完全相同的。任何人都可以考虑这种行为的原因吗?
祝你好运 塞巴斯蒂安
答案 0 :(得分:0)
如果查看查询计划,您会注意到第二个查询返回的行数明显减少(根据箭头的粗细来判断)。
这让我想知道您是否正确填充了compareHash
列。即如果所有200列都正确地包含在哈希中。
如果有的话,我希望第二个查询返回 more 行,因为散列字符数据会强制比较区分大小写。 sql server中的默认排序规则将对您对varchar值的第一个查询执行不区分大小写的比较。
虽然这与正确性有关,但您通常希望比较在比较性能时产生相同答案的方法。
除了正确性之外,另一个观察是在第一个查询中,数据被排序,然后应用流聚合。在第二个查询中,构建了一个哈希表,第二个表用于探测哈希表。您可以尝试通过在查询末尾添加OPTION (ORDER GROUP)
来强制排序第二个查询中的流聚合计划,看看是否会改变执行时间,但我怀疑它会改进它。
我的猜测是原始varchar数据有一些sql server在第一个查询中利用的自然顺序。
如果您愿意在compareHash
列上创建索引,那么您可能会在第二个查询中看到显着的性能提升,因为它将使用合并连接。