我有两张桌子:
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#代码填充节点表中的其余数据。
但令我困扰的是为什么加入如此小的表会给这个巨大的性能开销?还有更好的方法吗?
答案 0 :(得分:1)
查看解释计划:SQL Server(如果我的内存正确地为我服务)可以使用嵌套循环,散列或合并算法:如果嵌套循环出现在计划上(我怀疑),那么数据库将查找 - 即循环 - 较大表中每百万行中的每一行的小表,每个“父”行一个循环。如果使用合并,则需要更少的循环,但数据集很可能必须预先排序。对于散列连接,外部集可以从散列表中“查找”匹配的行。
对于设置大小中如此大的差异,开销并不是意料之外的:您可能也想尝试内联子查询,通常最好避免但是如果这样的大小差异,结果可能会令人惊讶。
答案 1 :(得分:0)