简化我的存储过程(cte、merge)

Simplifying my stored procedure (cte, merge)

提问人:DBanks 提问时间:10/30/2023 最后编辑:DaiDBanks 更新时间:10/30/2023 访问量:51

问:

我拼凑了一个相当长的、可能效率低下的存储过程。sproc 接收 SKU 的 JSON 以及一些参数,以便使用同一组数据批量更新两个不同的表。数据本身来自第一个表 (ProductValidation),因此这些数据将始终为 UPDATE,但第二个表可能包含也可能没有这些记录。(我只是将这两种情况都保留为合并 UPDATE 或 INSERT,即使第一种情况始终是 UPDATE - 但我认为这不会对性能造成太大影响......

如果您看到我可以做得更好的地方,请告诉我?我有点新手,所以期待你们的专业人士,谢谢!

WITH cte AS (

    SELECT
        SellingSkuCode AS SellingSkuCodez
    FROM
        OPENJSON( @json ) WITH (
            SellingSkuCode                varchar(100),
            MaterialDescription           varchar(8000),
            TranslatedMaterialDescription varchar(8000),
            LocalErpSubbrand              varchar(8000),
            HarmonizedSubbrand            varchar(500),
            GrossRevenue                  varchar(100),
            Priority                      varchar(100),
            Validated                     varchar(100),
            MarketUnitName                varchar(100),
            UpdatedBy                     varchar(100)
        )
),
cte2 AS (
    SELECT
        *
    FROM
        cte
        INNER JOIN ProductValidation B ON cte.SellingSkuCodez = B.SellingSkuCode
)
MERGE ProductValidation original
USING cte2 modified ON (
    original.SellingSkuCode = modified.SellingSkuCode
    AND
    original.MarketUnitName = @Market
)
WHEN MATCHED THEN UPDATE SET

    original.SellingSkuCode                = modified.SellingSkuCode,
    original.MaterialDescription           = modified.MaterialDescription,
    original.TranslatedMaterialDescription = modified.TranslatedMaterialDescription,
    original.LocalErpSubbrand              = modified.LocalErpSubbrand,
    original.HarmonizedSubbrand            = @HarmonizedSubbrand,
    original.GrossRevenue                  = modified.GrossRevenue,
    original.Priority                      = modified.Priority,
    original.Validated                     = modified.Validated,
    original.MarketUnitName                = @Market,
    original.UpdatedBy                     = @UpdatedBy

WHEN NOT MATCHED BY TARGET THEN
    INSERT (
        SellingSkuCode,
        MaterialDescription,
        TranslatedMaterialDescription,
        LocalErpSubbrand,
        HarmonizedSubbrand,
        GrossRevenue,
        Priority,
        Validated,
        MarketUnitName,
        UpdatedBy
    )
    VALUES (
        SellingSkuCode,
        modified.MaterialDescription, 
        modified.TranslatedMaterialDescription,
        modified.LocalErpSubbrand,
        @HarmonizedSubbrand,
        modified.GrossRevenue,
        modified.Priority,
        modified.Validated,
        @Market,
        @UpdatedBy
);


WITH cte AS (
    SELECT
        SellingSkuCode AS SellingSkuCodez
    FROM
        OPENJSON(@json) WITH (
            SellingSkuCode                varchar(100),
            MaterialDescription           varchar(8000),
            TranslatedMaterialDescription varchar(8000),
            LocalErpSubbrand              varchar(8000),
            HarmonizedSubbrand            varchar(500),
            GrossRevenue                  varchar(100),
            Priority                      varchar(100),
            Validated                     varchar(100),
            MarketUnitName                varchar(100),
            UpdatedBy                     varchar(100)
        )
),
cte2 AS (
    SELECT
        *
    FROM
        cte
        INNER JOIN ProductValidation B ON cte.SellingSkuCodez = B.SellingSkuCode
)
MERGE ProductValidation_Feedback original
USING cte2 modified ON (
    original.SellingSkuCode = modified.SellingSkuCode
    AND
    original.MarketUnitName = modified.MarketUnitName
)
WHEN MATCHED THEN UPDATE SET
    original.SellingSkuCode                = modified.SellingSkuCode,
    original.MaterialDescription           = modified.MaterialDescription,
    original.TranslatedMaterialDescription = modified.TranslatedMaterialDescription,
    original.LocalErpSubbrand              = modified.LocalErpSubbrand,
    original.HarmonizedSubbrand            = @HarmonizedSubbrand,
    original.GrossRevenue                  = modified.GrossRevenue,
    original.Priority                      = modified.Priority,
    original.Validated                     = modified.Validated,
    original.MarketUnitName                = @Market,
    original.UpdatedBy                     = @UpdatedBy

WHEN NOT MATCHED BY TARGET THEN
    INSERT (
        SellingSkuCode,
        MaterialDescription,
        TranslatedMaterialDescription,
        LocalErpSubbrand,
        HarmonizedSubbrand,
        GrossRevenue,
        Priority,
        Validated,
        MarketUnitName,
        UpdatedBy
    )
    VALUES (
        SellingSkuCode,
        modified.MaterialDescription,
        modified.TranslatedMaterialDescription,
        modified.LocalErpSubbrand,
        @HarmonizedSubbrand,
        modified.GrossRevenue,
        modified.Priority,
        modified.Validated,
        @Market,
        @UpdatedBy
);

我花了很长时间才让它发挥作用,因为我被困在加入 CTE 上。现在它可以工作了,但试图看看是否可以从速度/性能角度改进它。

SQL 性能 存储过程 合并 common-table-expression

评论

1赞 Dai 10/30/2023
1. 始终与 .2. 您应该对所有对象名称进行架构限定。3.SQL 服务器(以及大多数(全部?现在的RDBMS真的不喜欢有很多大列的表,因为它会导致表外存储,所以如果可能的话,考虑重新设计你的数据库。4.你确定要用代替这里吗?5. 您的子句应检查更改,以避免不必要的写入。6. 约定是将两个操作数表分别命名为 / 和 /HOLDLOCKMERGEvarcharvarcharnvarcharWHEN MATCHEDSELECT src.... EXCEPT SELECT tgt...MERGEtgtTARGETsrcSOURCE
0赞 NickW 10/30/2023
不要使用 SELECT *,只选择您实际要使用的列
0赞 NickW 10/30/2023
另外,cte2的意义何在?我只能认为你是在用它来修改。SellingSkuCode,但与 cte 具有相同的值。出售 SkuCodez 它似乎没有添加任何东西
0赞 DBanks 10/30/2023
嘿,@NickW,传入的 JSON 数据仅包含 SKU,不包含其他任何内容。CTE2 的目的是将 SKU 与其其余属性(即我们打算 UPDATE/INSERT 的完整记录)联接起来。
0赞 drum 10/31/2023
您使用的是什么 DBMS?

答: 暂无答案