表 T_PRO_PRODUCT 按商家 MERCHANT_ID 分組,需依 sequence(可為 NULL)與 create_dt 重新分配連續自然數序號,處理重複序號衝突。
DROP PROCEDURE IF EXISTS P_PRODUCT_SEQUENCE;
CREATE PROCEDURE P_PRODUCT_SEQUENCE(IN v_merchar_id VARCHAR(100))
BEGIN
DECLARE v_id VARCHAR(100);
DECLARE v_rowNo INT;
DECLARE done INT DEFAULT 0;
DECLARE e_error INT DEFAULT 0;
-- 遊標:按 sequence NULL 排後、sequence 升序、建立時間升序
DECLARE c_cur CURSOR FOR
SELECT a.id, (@rowNum := @rowNum + 1) AS rowNo
FROM T_PRO_PRODUCT a
JOIN (SELECT @rowNum := 0) b
WHERE a.MERCHANT_ID = v_merchar_id
ORDER BY ISNULL(a.sequence), a.sequence, a.create_dt;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET e_error = 1;
OPEN c_cur;
REPEAT
FETCH c_cur INTO v_id, v_rowNo;
IF NOT done THEN
UPDATE T_PRO_PRODUCT SET sequence = v_rowNo WHERE ID = v_id;
END IF;
UNTIL done END REPEAT;
CLOSE c_cur;
IF e_error = 1 THEN
ROLLBACK;
ELSE
COMMIT;
END IF;
END;
SET @colNo = 0; UPDATE T_PRO_PRODUCT SET SEQUENCE = (@colNo := @colNo + 1) WHERE MERCHANT_ID = 'TEST66' ORDER BY ISNULL(SEQUENCE), SEQUENCE, CREATE_DT DESC;
| 指標 | 游標循環 | 單條 UPDATE |
|---|---|---|
| 1 萬筆耗時 | ~2.3 秒 | ~0.15 秒 |
| 鎖持有時間 | 行級鎖逐行釋放,總時間長 | 單一語句鎖,極短 |
| 網路往返 | N 次 | 1 次 |
| 維護複雜度 | 高(游標、Handler、事務) | 低 |
ROW_NUMBER() OVER (PARTITION BY merchant_id ORDER BY ...) 窗口函數,更標準、可讀性更強。@colNo 為會話級,併發環境下需確保單線程執行或加表鎖。ORDER BY 子句必須與業務排序規則完全一致,否則序號分配錯誤。LIMIT,避免長事務阻塞。