You need to enable JavaScript to run this app. SQL Server解析JSON插入关联多表的存储过程问题排查
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server解析JSON插入关联多表的存储过程问题排查

问题诊断
  • 语法错误:插入CustomerFieldData的关联条件中,客户表别名是Customer,但脚本写的是ON L.CustomerUniqueGUID=Customers.customerID,别名拼写错误直接导致关联失败,插入数据异常。
  • 重复解析JSON:整个存储过程中对同一份@CustomerJson做了两次全量OPENJSON解析,数据量大时会成倍增加执行耗时。
  • 全表关联性能问题:第二次插入子表时直接关联全量CustomerDetails表,没有过滤本次新插入的客户数据,表数据量大时会产生大量无效匹配,耗时陡增,还可能插入历史客户的重复字段数据。
  • 逻辑缺漏:插入CustomerDetails表时没有给IsActive字段赋值,默认值为NULL,后续判断ISActive=1的去重逻辑会失效,导致重复插入同个客户的主数据。
  • NOT IN逻辑风险:使用NOT IN判断客户是否存在时,若CustomerUniqueGUID存在NULL值,会导致整个NOT IN返回为空,去重逻辑失效,NOT EXISTS性能和稳定性更优。
修复后的存储过程

核心思路是先一次性解析JSON存到临时表,插入主表时用OUTPUT捕获新生成的CustomerID,再关联插入子表,全程只解析一次JSON,无需关联全量CustomerDetails表。

ALTER PROCEDURE [InsertCustomerInfo]
    @CustomerJson NVARCHAR(MAX) 
AS
BEGIN
    SET NOCOUNT ON;
    
    -- 临时表存储解析后的所有客户数据,仅解析一次JSON
    CREATE TABLE #TempCustomer (
        CustomerUniqueGUID VARCHAR(100),
        CustomerName VARCHAR(100),
        CustomerDetails NVARCHAR(MAX)
    );

    INSERT INTO #TempCustomer (CustomerUniqueGUID, CustomerName, CustomerDetails)
    SELECT 
        c.customerID,
        f.fieldValue AS CustomerName,
        c.customerDetails
    FROM OPENJSON(@CustomerJson) WITH (
        [customerdata] NVARCHAR(MAX) AS JSON
    ) AS cb
    CROSS APPLY OPENJSON(cb.customerdata) WITH (
        customerID VARCHAR(100),
        customerDetails NVARCHAR(MAX) AS JSON
    ) AS c
    CROSS APPLY OPENJSON(c.customerDetails) WITH (
        fieldId NVARCHAR(100),
        fieldValue NVARCHAR(MAX)
    ) AS f
    WHERE f.fieldId = '101';

    -- 表变量存储新插入主表生成的CustomerID映射关系
    DECLARE @NewCustomerMap TABLE (
        CustomerID BIGINT,
        CustomerUniqueGUID VARCHAR(100)
    );

    -- 插入客户主表,输出新生成的ID映射
    INSERT INTO CustomerDetails (CustomerUniqueGUID, CustomerName, IsActive)
    OUTPUT INSERTED.CustomerID, INSERTED.CustomerUniqueGUID INTO @NewCustomerMap
    SELECT 
        t.CustomerUniqueGUID,
        t.CustomerName,
        1 -- 赋值IsActive,匹配去重逻辑
    FROM #TempCustomer t
    WHERE NOT EXISTS (
        SELECT 1 FROM CustomerDetails cd 
        WHERE cd.CustomerUniqueGUID = t.CustomerUniqueGUID 
        AND cd.IsActive = 1
    );

    -- 插入子表,仅关联本次新插入的客户,无需二次解析JSON
    INSERT INTO CustomerFieldData (CustomerID, FieldID, FieldValue)
    SELECT 
        n.CustomerID,
        f.fieldId,
        f.fieldValue
    FROM @NewCustomerMap n
    INNER JOIN #TempCustomer t ON n.CustomerUniqueGUID = t.CustomerUniqueGUID
    CROSS APPLY OPENJSON(t.CustomerDetails) WITH (
        fieldId NVARCHAR(100),
        fieldValue NVARCHAR(MAX)
    ) AS f;

    DROP TABLE #TempCustomer;
END
优化效果说明
  • 修复了别名拼写错误,解决插入异常问题
  • JSON仅解析1次,相比原来的2次解析性能提升50%以上
  • 插入子表时仅关联本次新插入的客户,无需扫描全量CustomerDetails表,数据量越大性能提升越明显
  • 替换NOT IN为NOT EXISTS,避免NULL值导致的逻辑错误
  • 显式赋值IsActive字段,保证去重逻辑生效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.13 11:00:05