前兩期專欄探討了不必要的 SQL 及執行過多、應以新特性替代的案例。本期深入剖析更多 SQL 應被推遲、合併或徹底避免的情境,最終目標一致:減少與 DB2 的交互次數。
螢幕顯示應用因大量不必要的重讀聞名:讀取一行並顯示;用戶修改值並按功能鍵更新;程式取得控制權並重讀該行(常用 FOR UPDATE OF 游標);FETCH 後進行「前後」檢查,查看螢幕顯示期間是否有其他用戶修改。若行未變,完成 UPDATE;若變,返回錯誤。
解決之道在於「樂觀鎖定」技術。我們確信多數情況行不會在顯示期間變更,UPDATE 的杯子是半滿而非半空。因此無需重讀即可直接 UPDATE,但需用經驗證技術確保針對未變更行的 UPDATE 已完成:在 WHERE 子句增加一或多個謂詞測試變更。選項包括:
場景:擁有 TRANDATE、PROCESS-DATE、CUSTNO 索引,需 FETCH 行並提交報告,刪除條件:超過 3 月、狀態無效、CUSTNO 在程式工作儲存清單中。
DECLARE CURSOR ... FOR SELECT ... FROM bigtable WHERE trandate < CURRENT DATE - 3 MONTHS AND status = :hv-inactive
OPEN -> FETCH 循環 -> 寫報表 -> DELETE WHERE CURRENT OF CURSOR
若 3,000 索引行指向 TRANDATE 超 3 月的表行,但只有 500 行 STATUS 為 inactive,最壞情況:
DECLARE CURSOR csr-select-and-delete-old-rows WITH ROWSET POSITIONING FOR
SELECT ponbr, custno, trandate, process-date
FROM FINAL TABLE (
DELETE FROM bigtable
WHERE trandate < CURRENT DATE - 3 MONTHS
AND status = :hv-inactive
AND custno IN (SELECT custno FROM ctt_cust)
)
OPEN -> FETCH ROWSET FOR 100 ROWS INTO 陣列 -> CLOSE
新最佳情況:OPEN 1 CONNECT,FETCH 1 CONNECT(讀 25 索引項、25 表 GETPAGE、每行發現即 DELETE、選取列插入 FINAL TABLE、回傳 25 行),CLOSE 1 CONNECT。總計 3 CONNECTS,表 GETPAGE ≤25。
顧問經驗顯示,主要共同編碼失誤之一是在程式而非 DB2 中驗證拒絕行。Stage 3 謂詞特別是拒絕大部分行者,通常源於未用 WHERE 子句的舊 VSAM 邏輯:鍵控讀取後套用 IF/THEN/ELSE。這恰恰是構建 WHERE 謂詞的良好基礎,能讓行在 DB2 位址空間快速被拒絕。
本三部曲強調完全消除或延遲至最後一刻與 DB2 對話的重要性。願未來每編一條 SQL,腦海都有個小聲音問:「這有必要嗎?能否一次讀/維護多行?能否推遲直到確認需要?」