通用禁用語句 (程序/函數/觸發器皆適用)
CHECK TABLE
LOCK TABLES / UNLOCK TABLES
LOAD DATA / LOAD TABLE
PREPARE / EXECUTE / DEALLOCATE PREPARE (動態 SQL)
OPTIMIZE TABLE
注意:5.0.13+ 放寬預存程序可用動態 SQL,但函數/觸發器仍禁用。
函數/觸發器額外禁用 (程序不受限)
| 類別 | 禁用語句/操作 | 原因 |
| 事務控制 | COMMIT、ROLLBACK、START TRANSACTION、隱含提交的 DDL | 函數需在單一語句內完成,不可跨事務 |
| 結果集返回 | SELECT (無 INTO)、SHOW、EXPLAIN | 函數必須返回單一標量值 |
| FLUSH | FLUSH TABLES/PRIVILEGES/LOGS 等 | 副作用不可控,觸發器調用程序間接受限 |
名稱解析優先序陷阱
MySQL 非標準行為:SELECT ... INTO var 中若欄位名與區域變數同名,優先解析為變數 (標準 SQL 優先欄位名)。
規避:區域變數加前綴 (如 v_、p_),避免與欄位重名。
元資料缺失:INFORMATION_SCHEMA.PARAMETERS
- 缺少參數元資料表,應用無法執行期檢視參數型別/預設值/模式。
- 規避:解析
SHOW CREATE PROCEDURE/FUNCTION 輸出或維護外部元資料庫。
除錯工具缺失
- 無內建步進除錯器、斷點、變數觀察。
- 替代:
SELECT ... INTO @debug_var 記錄關鍵點、寫入日誌表、使用 SIGNAL (5.5+) 拋出自訂錯誤碼。
游標實作差異
- 使用具體化游標:結果集全量在伺服器端建立並暫存,再逐行返回客戶端。
- 非原生游標:大結果集佔用臨時表空間,效能不如原生流式游標。
CALL 語句不可預處理
PREPARE stmt FROM 'CALL proc(?)'; 不支援,無論伺服器端/客戶端預處理。
快照隔離機制
- 語句開始時鎖定可見的程序/函數/觸發器版本快照。
- 同語句執行期間,其他連線的 DDL 修改對本語句不可見。
- 避免「執行中被修改」導致行為不一致,但也意味著熱部署需等待長查詢完成。
複寫風險總結
- 非確定性函數 (RAND、UUID、NOW) → 主從不一致。
- 非事務表部分更新 → 主從資料差異。
- 函數錯誤以 IGNORE 處理 → 靜默資料流失。
現代化建議
- 業務邏輯移出資料庫:應用層 (Java/Go/Python) 實作,享有完整除錯、測試、版控、CI/CD。
- 資料庫層僅保留:
・確定性純計算函數 (如稅率計算、單位換算)
・資料完整性觸發器 (審計欄位自動填充、軟刪除標記)
・效能關鍵路徑的原子化預存程序 (極少數)
- 複寫環境強制 RBR,並啟用
binlog_format=ROW + binlog_row_image=FULL。
結語
MySQL 預存子程序限制繁多、除錯困難、複寫風險高。「能在應用層做的,絕不在資料庫層做」 是現代架構鐵律。保留極少數確定性、高頻、效能敏感的常式,其餘全面下沉應用層。
- 上一篇文章: MySQL 伺服器端游標限制完整清單:唯讀、不可持久、不支援捲動與預處理語句綁定
- 下一篇文章: MySQL XA 分散式事務限制深度解析:僅支援 InnoDB、外部 XA 架構、內部 XA 缺失與崩潰恢復缺口
Copyright ©
程式碼之家 All Rights Reserved