在 SQL Server 上使用 3 个表连接时性能非常差
Posted
技术标签:
【中文标题】在 SQL Server 上使用 3 个表连接时性能非常差【英文标题】:Very bad performance using 3 tables join on SQL Server 【发布时间】:2017-06-25 15:04:57 【问题描述】:当我执行涉及以下 3 个表的 SQL 语句时,我遇到了严重的性能问题:
表A表C
特别是,这些表在数据仓库中,中间的表是维度表,而其他表是事实表。 TableA 大约有 900 万条记录,而 TableC 大约有 300 万条记录。维度表(TableB)只有74条记录。
查询的语法很简单,可以看到,其中TableA叫_PG,TableB等于_MDT,Table C叫_FM:
SELECT _MDT.codiceMandato as Customer, SUM(_FM.Totale) AS Revenue,
SUM(_PG.ErogatoTotale) AS Paid
FROM _PG INNER JOIN
_MDT
ON _PG.idMandato = _MDT.idMandato INNER JOIN
_FM
ON _FM.idMandato = _MDT.idMandato
GROUP BY _MDT.codiceMandato
实际上,我从未见过这个查询的结尾 :-( _PG 在 idMandato 和同一个 _FM 表上有一个非聚集索引 _MDT 表在 idMandato 上有一个聚集索引
执行计划如下
正如您所见,瓶颈是由于 Stream Aggregate(成本的 33%)和 Merge Join(成本的 66%)造成的。特别是,流聚合强调了大约 4000 亿的估计行! 我不知道原因,也不知道如何解决这个糟糕的问题。 我使用 SQL Server 2016 SP1 安装的虚拟服务器,Windows Server 2012 Standard 具有 4 个 Cpu 核心和 32 GB 的 RAM,1,5TB 在由具有 SSD 缓存的 SAS 磁盘组成的专用卷上。 希望有人能帮我理解。
提前致谢
【问题讨论】:
编辑您的问题并提供示例数据和所需的结果。目前尚不清楚您的表格到底是什么样子。 尝试将Totale
和ErogatoTotale
添加为非聚集索引的包含列。
估计可能是正确的 :-) 在两个事实表中,idMandato
可能非常不唯一,而您实际上执行了 M:N-join。根据您的实际问题,您可以在连接之前使用 CTE/派生表对每个事实表求和。
表1:N----1:1-----1:N之间的关系遵循星型模式。
【参考方案1】:
最可能的原因是因为您得到的是二维的笛卡尔积。这不必要地增加了行。解决方法是在做join
之前进行聚合。
您还没有提供示例数据,但想法是这样的:
SELECT m.codiceMandato as Customer, f.revenue, p.Paid
FROM _MDT m INNER JOIN
(SELECT p.idMandato, SUM(p.ErogatoTotale) AS Paid
FROM _PG p
GROUP BY p.idMandato
) p
ON p.idMandato = m.idMandato INNER JOIN
(SELECT f.idMandato, SUM(f.Totale) AS Revenue
FROM _FM f
GROUP BY f.idMandato
) f
ON f.idMandato = m.idMandato;
我不能 100% 确定这会解决问题,因为您的数据结构不清楚。
【讨论】:
不需要最终的 GROUP BY。 @dnoeth 。 . .谢谢。【参考方案2】:您可以尝试在不聚合的情况下在 TableA 和 TableC 之间进行子查询,然后将此子查询与 TableB 连接并应用 GROUP BY:
SELECT _MDT.codiceMandato, SUM(A.Totale) AS Revenue, sum( A.ErogatoTotale)
AS Paid
FROM ( SELECT m.idMandato, _FM.Totale, _PG.ErogatoTotale FROM _PG
INNER JOIN _FM
ON _FM.idMandato = _MDT.idMandato ) A
INNER JOIN _MDT ON A.idMandato = _MDT.idMandato
GROUP BY _MDT.codiceMandato
【讨论】:
以上是关于在 SQL Server 上使用 3 个表连接时性能非常差的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server 使用 2 个表(外键?) ASP.NET