我有以下查询:
SELECT fpa.scenario_id,
fpa.facility_id,
cge.CostGroupId result_total_id,
mp_surrogate_id,
CAST(SUM(fpa.raw_amount * cge.CostSign) AS DECIMAL(25, 13))
result_total_amount
INTO ADM_FactProfitTotalAmount_1
FROM #tempAmount fpa
JOIN ResultTest cge ON cge.CostId = fpa.process_id
WHERE fpa.scenario_id = 1
GROUP BY fpa.scenario_id, fpa.facility_id, cge.CostGroupId, fpa.mp_surrogate_id
#tempAmount
我有2.2亿行。ResultTest
我有150行。我有#tempAmount
的索引:
CREATE NONCLUSTERED INDEX #tempAmount_process_id
ON #tempAmount(scenario_id, facility_id, mp_surrogate_id, process_id )
执行大约需要1个小时。是否有可能对其进行优化?
编辑:
我在ResultTest列CostId上创建了索引,更改了一些其他索引和查询
CREATE CLUSTERED INDEX #tempFactAmount_index
ON #tempAmount (process_id ,facility_id, mp_surrogate_id )
SELECT ISNULL(CAST(1 as BIGINT), 0) scenario_id,
fpa.facility_id,
cge.CostGroupId result_total_id,
fpa.mp_surrogate_id,
CAST(SUM(fpa.raw_amount * cge.CostSign) AS DECIMAL(25, 13)) result_total_amount
INTO ADM_FactProfitTotalAmount_1
FROM ResultTest cge
JOIN #tempAmount fpa ON cge.CostId = fpa.process_id
GROUP BY fpa.facility_id, fpa.mp_surrogate_id, cge.CostGroupId
执行计划:
41%插入ADM_FactProfitTotalAmount_1
51%哈希匹配聚合
2%哈希匹配内部联接
答案 0 :(得分:2)
在这样的场景中,我发现在加入较小的表之前对较大表中的金额求和通常会有所帮助。所以在这种情况下我会使用以下内容:
;WITH SUMCTE
AS
(
SELECT fpa.facility_id,
fpa.mp_surrogate_id,
fpa.process_id,
SUM(fpa.raw_amount) AS total_amount
FROM #tempAmount fpa
GROUP BY fpa.facility_id, fpa.mp_surrogate_id, fpa.process_id
)
SELECT CAST(1 as BIGINT) AS Scenario_id,
facility_id,
cge.CostGroupId result_total_id,
mp_surrogate_id,
CAST(SUM(SCT.total_amount * cge.CostSign) AS DECIMAL(25, 13)) result_total_amount
INTO ADM_FactProfitTotalAmount_1
FROM ResultTest cge
JOIN SUMCTE SCT ON cge.CostId = SCT.process_id
GROUP BY fpa.facility_id, fpa.mp_surrogate_id, cge.CostGroupId
如果每个process_id在ResulTest中只有一行,我会通过删除外部组来进一步简化:
;WITH SUMCTE
AS
(
SELECT fpa.facility_id,
fpa.mp_surrogate_id,
fpa.process_id,
SUM(fpa.raw_amount) AS total_amount
FROM #tempAmount fpa
GROUP BY fpa.facility_id, fpa.mp_surrogate_id, fpa.process_id
)
SELECT CAST(1 as BIGINT) AS Scenario_id,
facility_id,
cge.CostGroupId result_total_id,
mp_surrogate_id,
CAST((SCT.total_amount * cge.CostSign) AS DECIMAL(25, 13)) result_total_amount
INTO ADM_FactProfitTotalAmount_1
FROM ResultTest cge
JOIN SUMCTE SCT ON cge.CostId = SCT.process_id
答案 1 :(得分:1)
我建议从检查预计执行计划开始 http://msdn.microsoft.com/en-us/library/ms191194.aspx
多列索引只有在前缀为前缀时才能使用。 http://dev.mysql.com/doc/refman/5.0/en/multiple-column-indexes.html
所以我建议在scenario_id旁边移动process_id,因为它们用在where和join中。
创建NONCLUSTERED INDEX #tempAmount_process_id ON #tempAmount(scenario_id,process_id,facility_id,mp_surrogate_id)
最后一个:让OS尽可能地将磁盘块缓存到内存中。 在linux之前,一些性能关键数据库投入生产, 做“cat your_database.store.file> / dev / null”。 将从内存缓存中点击大量磁盘读取。
答案 2 :(得分:1)
首先,我建议捕获实际的执行计划。如果从SQL Server Management Studio(SSMS)运行查询,请启用“包括实际执行计划”选项。如果此查询从另一个程序运行,请运行SQL Server Profiler并打开Showplan Statistics Profile和/或Showplan XML Statistics Profile。查看此配置文件,查看查询是否符合您的预期。
你有关于ResultTest colum CostId的索引吗?只有150行,此表上的索引扫描不是什么大问题。如果您在此表上没有索引,则可以尝试使用它。
我想知道执行计划是否正在执行嵌套循环以加入ResultTest。如果是这样,那将是150 X 220,000,000 = 330亿次操作。如果是这种情况,散列连接或合并连接将表现得更好。您可以使用联接提示OPTION (HASH JOIN)
或OPTION (MERGE JOIN)
强制执行特定联接。仅这一点就可以产生巨大的差异。
#tempAmount上的索引包含许多SELECT
查询不需要的列。此外,它是NONCLUSTERED
索引。是否还有一个CLUSTERED指数?如果没有,您可以尝试将其转换为CLUSTERED
并删除其他列。这将减小索引的大小并且应该执行得更好,因为scenario_id的所有行都是连续的。