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
相关产品推荐
相关产品推荐

