4

我有以下查询:

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% 哈希匹配内连接

4

3 回答 3

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 
于 2012-12-06T11:13:47.167 回答
1

首先,我建议捕获实际的执行计划。如果您从 SQL Server Management Studio (SSMS) 运行查询,请打开“包括实际执行计划”选项。如果此查询是从另一个程序运行的,请运行 SQL Server Profiler 并打开 Showplan Statistics Profile 和/或 Showplan XML Statistics Profile。查看此配置文件并查看查询的行为是否符合您的预期。

你有关于 ResultTest 列 CostId 的索引吗?只有 150 行,对这个表进行索引扫描没什么大不了的。如果您在此表上没有索引,您可以尝试一下。

我想知道执行计划是否正在执行嵌套循环以加入 ResultTest。如果是这样,那将是 150 X 220,000,000 = 330 亿次操作。如果是这种情况,散列连接或合并连接会执行得更好。您可以使用连接提示OPTION (HASH JOIN)OPTION (MERGE JOIN). 仅此一项就可以产生巨大的影响。

#tempAmount 上的索引有很多查询不需要的列SELECT。此外,它是一个NONCLUSTERED索引。是否还有 CLUSTERED 索引?如果没有,您可以尝试将其转换为CLUSTERED并删除其他列。这将减小索引的大小并且性能应该更好,因为scenario_id 的所有行都是连续的。

于 2012-12-05T14:05:05.763 回答
1
  • 我建议从检查估计的执行计划开始。
    http://msdn.microsoft.com/en-us/library/ms191194.aspx

  • 多列索引只有在保留前缀时才能使用。 http://dev.mysql.com/doc/refman/5.0/en/multiple-column-indexes.html

    所以我建议将 process_id 移到scenario_id 旁边,因为它们用于 where 和 join。

    创建非聚集索引 #tempAmount_process_id ON #tempAmount(scenario_id, process_id, facility_id, mp_surrogate_id)

  • 最后一个:让操作系统尽可能多地将你的磁盘块缓存到内存中。在 linux 中,在一些性能关键的数据库投入生产之前,请执行“cat your_database.store.file > /dev/null”。大量磁盘读取将从内存缓存中命中。

于 2012-12-05T11:43:04.893 回答