存储过程的优化(存储过程修改说明及优化方案)

存储过程的优化(存储过程修改说明及优化方案)

admin 2025-10-25 社会资讯 17 次浏览 0个评论

存储过程的优化(存储过程修改说明及优化方案)
(图片来源网络,侵删)

一、修改背景与目标

原存储过程逻辑为删除并全量重建采购入库单扩展字段表(`rdrecords01_extradefine`)中的请购部门信息(`cbdefine7`),存在以下问题:

1. 数据覆盖风险:全量删除可能导致历史数据丢失(若上游数据异常)。

2. 性能损耗:对大量数据频繁删除+插入,易引发锁表或事务日志膨胀。

优化目标:

仅对新增/更新的入库单记录(即`cbdefine7`为空或变更的记录)执行更新操作,保留历史有效数据。

二、核心逻辑调整

1. 移除全量删除操作

删除原存储过程开头的 `DELETE FROM UFDATA_004_2017.dbo.rdrecords01_extradefine` 语句,避免全表清空。

2. 调整CTE查询范围

CTE(公用表表达式)仅筛选需要更新的记录:

- 采购入库单列表(`zpurRkdList`)中未维护请购部门的记录(即`rdrecords01_extradefine.cbdefine7 IS NULL`)。

- 或需增量更新的记录(可通过时间戳/版本号判断,此处暂以`NULL`为例)。

3. 从“删除+插入”改为“条件更新”

通过 `MERGE` 或 `UPDATE` 语句,将CTE计算出的请购部门信息增量更新到扩展字段表,而非全量重建。

三、修改后的存储过程代码

```sql

CREATE PROCEDURE AA_extradefine_rdrecords01_cbdefine7

AS

BEGIN

SET NOCOUNT ON; -- 关闭计数,提升性能

-- 定义CTE:计算需要更新的请购部门信息(仅包含cbdefine7为空的记录)

WITH CTE AS (

SELECT

zpurrkdlist.autoid,

ISNULL(MAX(tt.ccode), MAX(dd.ccode)) AS 请购单, -- 优先取采购订单来源的请购单,其次委外订单

ISNULL(MAX(tt.采购请购部门), MAX(dd.委外请购部门)) AS 部门 -- 合并采购/委外来源的请购部门(取最新单据)

FROM

zpurRkdList WITH (NOLOCK) -- 采购入库单列表(nolock避免阻塞)

-- 关联扩展字段表,筛选cbdefine7为空的记录(需更新的数据)

LEFT JOIN rdrecords01_extradefine ex WITH (NOLOCK)

ON ex.autoid = zpurrkdlist.autoid

AND ex.cbdefine7 IS NULL -- 仅处理未维护请购部门的记录

-- 关联采购订单信息(含请购部门)

LEFT JOIN (

SELECT

cpoid AS 订单编号,

cinvcode AS 存货编码,

cdepname2 AS 采购请购部门,

ccode -- 请购单编号(用于取最新)

FROM zpurpoheader ph WITH (NOLOCK)

INNER JOIN zpurpotail pt WITH (NOLOCK) ON ph.poid = pt.poid

LEFT JOIN pu_AppHead ah WITH (NOLOCK) ON ph.cupsocode = ah.ccode -- 关联请购单头表获取部门

) tt ON zpurrkdlist.cpoid = tt.订单编号 AND zpurrkdlist.cinvcode = tt.存货编码

-- 关联委外订单信息(含请购部门)

LEFT JOIN (

SELECT

om_mohead.ccode AS 订单编号, -- 委外订单编号

om_mobody.cinvcode AS 存货编码,

cdepname2 AS 委外请购部门,

cc.ccode -- 请购单编号(用于取最新)

FROM om_mohead WITH (NOLOCK)

INNER JOIN om_mobody WITH (NOLOCK) ON om_mohead.moid = om_mobody.moid

LEFT JOIN (

SELECT ccode, cdepname AS cdepname2 FROM pu_AppHead -- 委外请购部门来源

) cc ON om_mobody.cupsocode = cc.ccode

) dd ON zpurrkdlist.cpoid = dd.订单编号 AND zpurrkdlist.cinvcode = dd.存货编码

WHERE

ex.autoid IS NOT NULL -- 仅处理已存在于扩展表但cbdefine7为空的记录

-- 可添加时间条件实现增量更新,例如:zpurrkdlist.dDate >= DATEADD(DAY, -1, GETDATE())

GROUP BY

zpurrkdlist.autoid -- 按入库单明细行分组

)

-- 增量更新扩展字段表:将CTE计算的部门信息更新到rdrecords01_extradefine.cbdefine7

UPDATE ex

SET ex.cbdefine7 = cte.部门

FROM rdrecords01_extradefine ex

INNER JOIN CTE ON ex.autoid = CTE.autoid

WHERE CTE.部门 IS NOT NULL; -- 仅更新有有效部门信息的记录

-- (可选)若扩展表中不存在记录,补充插入(避免漏导)

INSERT INTO rdrecords01_extradefine (autoid, cbdefine7)

SELECT

cte.autoid,

cte.部门

FROM CTE

LEFT JOIN rdrecords01_extradefine ex ON ex.autoid = cte.autoid

WHERE

ex.autoid IS NULL -- 扩展表中不存在该autoid的记录

AND cte.部门 IS NOT NULL; -- 确保部门信息有效

SET NOCOUNT OFF;

END

```

四、关键优化点说明

1. 增量更新逻辑:

- 通过 `LEFT JOIN rdrecords01_extradefine ex ON ... AND ex.cbdefine7 IS NULL` 筛选需更新的记录,避免全表扫描。

- 若需支持历史数据修复,可移除 `ex.cbdefine7 IS NULL` 条件,或增加时间范围(如近1个月未更新的记录)。

2. 数据优先级处理:

- 请购部门优先取采购订单来源(`tt.采购请购部门`),其次委外订单(`dd.委外请购部门`),通过 `ISNULL(MAX(tt...), MAX(dd...))` 实现。

- 若同一入库单行对应多个请购单,通过 `MAX(tt.ccode)/MAX(dd.ccode)` 取最新请购单的部门(假设`ccode`为按时间递增的单号)。

3. 性能优化:

- 使用 `WITH (NOLOCK)` 减少锁竞争(需业务允许脏读)。

- 通过 `GROUP BY autoid` 确保每个入库单明细行只更新一次。

- 拆分“更新”与“插入”逻辑,避免 `MERGE` 语句的潜在死锁风险。

五、使用建议

1. 执行频率:建议按小时/日调度执行,避免实时触发(如每小时更新近24小时新增的入库单)。

2. 数据校验:更新后可通过以下SQL验证结果:

```sql

SELECT TOP 100 autoid, cbdefine7 AS 请购部门

FROM rdrecords01_extradefine

WHERE cbdefine7 IS NOT NULL

ORDER BY autoid DESC;

```

3. 异常处理:可添加 `TRY...CATCH` 块记录错误日志,例如:

```sql

BEGIN TRY

-- 主逻辑

END TRY

BEGIN CATCH

INSERT INTO ErrorLog (ProcName, ErrorMsg, ErrorTime)

VALUES ('AA_extradefine_rdrecords01_cbdefine7', ERROR_MESSAGE(), GETDATE());

END CATCH

```

六、总结

修改后的存储过程通过增量更新替代全量重建,显著降低了数据操作风险和性能损耗,同时保留了原有的请购部门逻辑(采购订单优先、多来源合并、取最新请购单)。适用于用友U8等ERP系统中采购入库单扩展字段的日常维护场景。

转载请注明来自海坡下载,本文标题:《存储过程的优化(存储过程修改说明及优化方案)》

每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,17人围观)参与讨论

还没有评论,来说两句吧...