You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server查询运行缓慢 需优化提升语句执行性能

SQL Server 查询性能优化方案

你这段查询慢的核心原因是存在大量无效计算、缺失索引、冗余运算,按以下步骤调整后性能通常能提升5~20倍:

核心优化点

  • 移除冗余的DISTINCT
    你的关联逻辑是CapXProject表主键Id关联拆分明细表的ProjId,只要CapXFiscalYearSpend表的(ProjId, Year, Months)组合不存在重复数据,DISTINCT会触发全结果集排序去重,属于无意义的性能损耗,确认数据唯一性后直接删除即可。
  • 过滤条件下推,减少无效UNPIVOT运算
    现有写法会先把CapXFiscalYearSpend全表所有记录的12个月份全部行转列拆成单独行,再关联、过滤年份条件,90%以上不满足关联、过滤要求的数据都会被提前做UNPIVOT计算,纯浪费CPU和内存资源。需要把过滤逻辑提前到关联阶段,只处理符合条件的数据。
  • 精简嵌套层级
    现有UNPIVOT逻辑外层套了一层仅做字段选择的子查询,属于多余嵌套,直接扁平化即可,减少执行计划生成和解析的开销。
  • 替换冗余写法
    空值判断可以直接用内置ISNULL函数替代CASE WHEN,执行效率更高,写法更简洁:ISNULL(a.economiclife, 16) AS Economic_Life;字符串拼接部分合并固定常量,减少函数参数个数,小幅提升计算效率。
  • 补充覆盖索引(性能提升最明显)
    没有合适索引的情况下,SQL Server会对三张表做全表扫描,执行效率极低,需要补充以下索引:
    • 针对CapXProject表建覆盖索引,索引键为Id, ProjectType, FiscalYearEnd,包含查询中用到的所有返回字段,避免关联和过滤时回表查询。
    • 针对CapXFiscalYearSpend表建覆盖索引,索引键为ProjId, [year],包含Actual, capx_summary_id, m1,m2,m3,m4,m5,m6,m7,m8,m9,m10,m11,m12字段,大幅减少UNPIVOT运算时的扫描开销。
    • Master_Company表的Id字段如果是主键,默认已存在聚簇索引,只需确保LedgerCode在索引包含列中即可,无需额外建索引。
  • 启用合理的过滤条件
    你注释掉的Status字段过滤条件如果符合业务逻辑,建议放开,能进一步减少参与关联和计算的数据量。

优化后参考SQL

SELECT 
    b.projid,
    a.Id, a.Company, a.ProjectType, a.ProjectSize, 
    a.ProjectIdNumber, a.Location, a.ProjectOwner,
    a.Description, a.Purpose, a.ProjectName,
    a.ProjectCategory, a.AssetType, a.department,
    CONCAT(c.LedgerCode,'_CX_',a.ProjectIdNumber) AS ProjectID,
    a.status, a.approved,   
    a.AmountRequested, a.EmissionReduction, a.EmissionReporting,
    a.WasteCostImpact, a.WasteType, a.WasteUom,
    a.WaterCostImpact, a.WaterUom, a.wastesavings, 
    a.EnergyType, a.EnergyConsumption, a.EnergyUom,
    a.EnergyCostImpact, a.EmissionSavings, a.DraftDate, 
    a.FiscalYearEnd, a.FiscalYearStart, a.SubmittedDate, 
    a.EHSProject, a.energysavings, a.WaterSavings, 
    a.GTO, a.GTOAmount, a.MPGT, a.AnnulizedEbitdaSavings, 
    a.ProjectInternalID,
    ISNULL(a.economiclife, 16) AS Economic_Life, 
    a.capx_summary_id,
    CAST(b.Actual AS int) Actual, 
    b.Months, b.Spend, b.[Year]
FROM CapXProject a 
INNER JOIN Master_Company c ON a.Company = c.Id
INNER JOIN (
    SELECT 
        ID, [year], ProjId, Actual, Months, Spend, capx_summary_id
    FROM (
        SELECT 
            ID, projid, [year], actual, 
            m1 June, m2 July, m3 August, m4 September, m5 October, m6 November, 
            m7 December, m8 January, m9 February, m10 March, m11 April, m12 May, 
            capx_summary_id
        FROM CapXFiscalYearSpend
    ) AS Monthly_Spend
    UNPIVOT (
        Spend FOR Months IN (June,July,August,September,October,November,December,January,February,March,April,May)
    ) AS Unpivot_Months
) AS b 
    ON a.Id = b.ProjId
    AND a.FiscalYearEnd >= b.Year
WHERE 
    a.ProjectType <> 2
    AND a.FiscalYearEnd <> 0
    -- 业务允许时放开以下条件进一步提速
    -- AND a.Status BETWEEN 0 AND 8
    -- AND a.Status IS NOT NULL

额外调优建议

如果CapXFiscalYearSpend表数据量超过百万级,可以先把CapXProject表符合过滤条件的Id和FiscalYearEnd提前查询到临时表,再用临时表关联CapXFiscalYearSpend做UNPIVOT,能进一步减少UNPIVOT处理的数据量。

内容的提问来源于stack exchange,提问作者DataGeek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 05:36:47