SQL:奇怪的查询性能行为

时间:2014-11-29 10:57:01

标签: sql sql-server sqlperformance

我有两张桌子:

  • Nodes - 非常小的桌子,大约20行
  • Events - 相当大的桌子,大约10M行

以及以下查询:

select 
    e.DeviceAlias as Mac, n.NodeId, n.city as City, n.street as Street, e.Status,
    CASE WHEN e.Status = 'U' THEN 'Unknown' ELSE 'Known' END as 'Source', 
    COUNT (*) as 'Count', 
    SUM(CASE WHEN e.SentMessageId > 0 THEN 1 ELSE 0 END) as SentMsgCount
from 
    events e
join 
    Nodes n on e.NodeId = n.NodeId
where
    e.InsertDate >= @startdate
    and e.InsertDate <= @enddate
group by 
    e.DeviceAlias, e.Status, n.NodeId, n.city, n.street

查询执行时间超过5分钟。我已经应用了所有必需的索引,并且sql perf advisor建议没有其他索引或统计信息。但是,如果我摆脱了连接并执行以下查询:

select 
    e.DeviceAlias as Alias, NodeId,
    CASE WHEN e.Status = 'U' THEN 'Unknown' ELSE 'Known' END as 'Source', 
    COUNT (*) as 'Count', 
    SUM(CASE WHEN e.SentMessageId > 0 THEN 1 ELSE 0 END) as SentMsgCount
from 
    events e
where
    e.InsertDate >= '2014-07-01'
    and e.InsertDate <= '2014-11-28'
group by 
    e.DeviceAlias,nodeid, e.Status

它在30秒内执行。

简单的解决方案是使用第二个查询并用c#代码填充节点表中的其余数据。

但令我困扰的是为什么加入如此小的表会给这个巨大的性能开销?还有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

查看解释计划:SQL Server(如果我的内存正确地为我服务)可以使用嵌套循环,散列或合并算法:如果嵌套循环出现在计划上(我怀疑),那么数据库将查找 - 即循环 - 较大表中每百万行中的每一行的小表,每个“父”行一个循环。如果使用合并,则需要更少的循环,但数据集很可能必须预先排序。对于散列连接,外部集可以从散列表中“查找”匹配的行。

对于设置大小中如此大的差异,开销并不是意料之外的:您可能也想尝试内联子查询,通常最好避免但是如果这样的大小差异,结果可能会令人惊讶。

答案 1 :(得分:0)

埃里克卡伦,你是我的男人;) 更新统计信息可将执行时间缩短至38秒! 无论如何 - WTF ??我在此数据库上将自动更新统计信息设置为true ...事件表的增长非常快,因此自动更新应该每隔几个小时进行一次,根据&#34;表有超过500行,并且增加了500 +自上次更新以来表格大小的20%&#34;规则(来自http://www.pythian.com/blog/sql-server-statistics-maintenance-and-best-practices/