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

如何优化SQL查询:减少JOIN操作数量的方法

SQL查询优化建议

针对你当前查询中存在的多JOIN重复、冗余子查询问题,以下是具体优化方案,无需为每个JOIN单独创建表:

1. 提取重复JOIN逻辑为CTE

你的两个子查询ASMT和Cut都重复执行了tCustomer → tContract → tContractProgram → tOperationalProgram → tPackage → tJobs的JOIN链,这会导致数据库重复计算。可以用**公共表表达式(CTE)**将这部分逻辑提取出来,复用结果:

WITH BaseJobData AS (
    SELECT 
        J.JobAssessID,
        J.JobID,
        CU.Customer,
        OP.ProgramName
    FROM tCustomer CU
    INNER JOIN tContract CN ON CU.CustomerID = CN.CustomerID
    INNER JOIN tContractProgram CP ON CN.ContractID = CP.ContractID
    INNER JOIN tOperationalProgram OP ON OP.ContractProgramID = CP.ContractProgramID
    INNER JOIN tPackage P ON OP.PackageID = P.PackageID
    INNER JOIN tJobs J ON P.PackageID = J.PackageID
    WHERE CU.Customer = 'TRANSGRID' 
      AND OP.ProgramName = 'Lidar Works 21-22 FY'
)

2. 合并相似子查询减少JOIN

ASMT和Cut子查询结构高度相似,仅过滤条件不同,可以合并为一个子查询,通过字段标记区分两类数据,避免额外的JOIN操作:

WITH BaseJobData AS (
    -- 上述BaseJobData内容
),
CombinedActivitySOR AS (
    SELECT 
        SOR.JobAssessID,
        SOR.BOMDate,
        SOR.SORItemCode_Short,
        SOR.SORItemCode,
        SOR.LineTotal,
        SOR.SORItemQty,
        ACT.ActivityType,
        ACT.Action,
        ACT.Status,
        -- 标记数据类型
        CASE WHEN ACT.ActivityType IN ('Assessment', 'Update') THEN 'ASMT'
             WHEN ACT.ActivityType = 'Cutting' AND ACT.Status = 'Complete' THEN 'CUT'
             ELSE NULL END AS DataCategory
    FROM BaseJobData BJD
    INNER JOIN tActivity ACT ON ACT.JobAssessID = BJD.JobAssessID
    INNER JOIN AM6_SORITEM SOR ON SOR.SourceID = ACT.ActivityID 
                              AND SOR.JobID = ACT.JobID 
                              AND SOR.JobAssessID = ACT.JobAssessID 
    WHERE SOR.LineTotal <> 0
      AND (
          (ACT.ActivityType IN ('Assessment', 'Update'))
          OR
          (ACT.ActivityType = 'Cutting' AND ACT.Status = 'Complete')
      )
)

3. 简化LOOKUP子查询

原查询中LVFN子查询可以直接JOIN原表,或者如果这个LOOKUP逻辑经常使用,创建一个持久化视图替代临时子查询,避免重复执行过滤:

-- 直接JOIN方式替代子查询
LEFT JOIN [Active].[dbo].[LOOKUPVALUE_EVW] LVFN
    ON LVFN.LookupId = (SELECT LookupID FROM [Active].[dbo].[LOOKUP_EVW] WHERE Name = 'List_NoticeMethod')
    AND LVFN.Code = TT.FieldNotification

-- 或者创建持久化视图(如果复用率高)
CREATE VIEW vList_NoticeMethod AS
SELECT LV.Code, LV.[Description]
FROM [Active].[dbo].[LOOKUP_EVW] L
INNER JOIN [Active].[dbo].[LOOKUPVALUE_EVW] LV ON L.LookupID = LV.LookupId
WHERE L.Name = 'List_NoticeMethod';

-- 之后查询直接用视图
LEFT JOIN vList_NoticeMethod LVFN ON LVFN.Code = TT.FieldNotification

4. 最终整合后的查询示例

将上述优化点整合,完整查询如下:

WITH BaseJobData AS (
    SELECT 
        J.JobAssessID,
        J.JobID,
        CU.Customer,
        OP.ProgramName
    FROM tCustomer CU
    INNER JOIN tContract CN ON CU.CustomerID = CN.CustomerID
    INNER JOIN tContractProgram CP ON CN.ContractID = CP.ContractID
    INNER JOIN tOperationalProgram OP ON OP.ContractProgramID = CP.ContractProgramID
    INNER JOIN tPackage P ON OP.PackageID = P.PackageID
    INNER JOIN tJobs J ON P.PackageID = J.PackageID
    WHERE CU.Customer = 'TRANSGRID' 
      AND OP.ProgramName = 'Lidar Works 21-22 FY'
),
CombinedActivitySOR AS (
    SELECT 
        SOR.JobAssessID,
        SOR.BOMDate,
        SOR.SORItemCode_Short,
        SOR.SORItemCode,
        SOR.LineTotal,
        SOR.SORItemQty,
        ACT.ActivityType,
        ACT.Action,
        ACT.Status,
        CASE WHEN ACT.ActivityType IN ('Assessment', 'Update') THEN 'ASMT'
             WHEN ACT.ActivityType = 'Cutting' AND ACT.Status = 'Complete' THEN 'CUT'
             ELSE NULL END AS DataCategory
    FROM BaseJobData BJD
    INNER JOIN tActivity ACT ON ACT.JobAssessID = BJD.JobAssessID
    INNER JOIN AM6_SORITEM SOR ON SOR.SourceID = ACT.ActivityID 
                              AND SOR.JobID = ACT.JobID 
                              AND SOR.JobAssessID = ACT.JobAssessID 
    WHERE SOR.LineTotal <> 0
      AND (
          (ACT.ActivityType IN ('Assessment', 'Update'))
          OR
          (ACT.ActivityType = 'Cutting' AND ACT.Status = 'Complete')
      )
)
SELECT 
    -- 这里放入你需要的主查询字段
    BJD.JobAssessID,
    BJD.JobID,
    -- ASMT相关字段
    ASMT.BOMDate AS ASMT_BOMDate,
    ASMT.SORItemCode_Short AS ASMT_SORItemCode_Short,
    -- Cut相关字段
    Cut.BOMDate AS Cut_BOMDate,
    Cut.Status AS Cut_Status,
    -- 其他关联表字段
    t.*,
    TL.*,
    TT.*,
    LVFN.[Description]
FROM BaseJobData BJD
LEFT JOIN AM6_TASK t ON BJD.JobAssessID = t.JobAssessID
LEFT JOIN vTransgrid_LIDAR TL ON TL.JobAssessID = BJD.JobAssessID
LEFT JOIN Active.dbo.EXT_TASK_TRANSGRID_EVW TT ON TT.TaskID = BJD.JobID
LEFT JOIN vList_NoticeMethod LVFN ON LVFN.Code = TT.FieldNotification
LEFT JOIN CombinedActivitySOR ASMT 
    ON BJD.JobAssessID = ASMT.JobAssessID 
    AND ASMT.DataCategory = 'ASMT'
LEFT JOIN CombinedActivitySOR Cut 
    ON BJD.JobAssessID = Cut.JobAssessID 
    AND Cut.DataCategory = 'CUT'
    AND Cut.SORItemCode = ASMT.SORItemCode;

额外优化建议

  • 索引优化:确保以下字段存在合适的索引:
    • 连接字段:tCustomer.CustomerID, tContract.CustomerID, tContract.ContractID, tContractProgram.ContractID, tOperationalProgram.ContractProgramID, tPackage.PackageID, tJobs.PackageID, tActivity.JobAssessID, AM6_SORITEM.SourceID/JobID/JobAssessID
    • 过滤字段:tCustomer.Customer, tOperationalProgram.ProgramName, tActivity.ActivityType, tActivity.Status, AM6_SORITEM.LineTotal
  • 避免不必要的LEFT JOIN:如果某些LEFT JOIN的结果不可能为NULL(比如业务上必然存在关联),可以改为INNER JOIN减少数据库计算量。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 06:02:31