文件首頁
MySQL 9.0 參考手冊
相關文件 下載本手冊
PDF (美式信紙) - 40.0Mb
PDF (A4) - 40.1Mb
Man Pages (TGZ) - 258.2Kb
Man Pages (Zip) - 365.3Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 9.0 參考手冊  /  儲存物件  /  儲存程式的限制

27.9 儲存程式的限制

這些限制適用於第 27 章儲存物件中描述的功能。

這裡提到的一些限制適用於所有儲存常式;也就是說,同時適用於儲存程序和儲存函數。也有一些特定於儲存函數但不適用於儲存程序的限制。

儲存函數的限制也適用於觸發器。也有一些特定於觸發器的限制。

儲存程序的限制也適用於事件排程器事件定義的 DO 子句。也有一些特定於事件的限制。

儲存常式中不允許的 SQL 語句

儲存常式不能包含任意 SQL 語句。不允許使用以下語句

  • 鎖定語句 LOCK TABLESUNLOCK TABLES

  • ALTER VIEW.

  • LOAD DATALOAD XML

  • SQL 預備語句 (PREPAREEXECUTEDEALLOCATE PREPARE) 可以在儲存程序中使用,但不能在儲存函數或觸發器中使用。因此,儲存函數和觸發器不能使用動態 SQL (您在其中將語句建構成字串,然後執行它們)。

  • 一般來說,SQL 預備語句中不允許使用的語句在儲存程式中也不允許使用。如需支援作為預備語句的語句清單,請參閱第 15.5 節,「預備語句」。例外情況是 SIGNALRESIGNALGET DIAGNOSTICS,這些語句不允許作為預備語句,但允許在儲存程式中使用。

  • 因為區域變數的作用域僅限於儲存程式執行期間,因此在儲存程式中建立的預備語句中不允許參照它們。預備語句的作用域是目前的工作階段,而不是儲存程式,因此該語句可能會在程式結束後執行,屆時這些變數將不再在作用域中。例如,SELECT ... INTO local_var 不能用作預備語句。此限制也適用於儲存程序和函數參數。請參閱第 15.5.1 節,「PREPARE 語句」

  • 在所有儲存程式 (儲存程序和函數、觸發器和事件) 中,剖析器將 BEGIN [WORK] 視為 BEGIN ... END 區塊的開頭。若要在此內容中開始交易,請改用 START TRANSACTION

儲存函數的限制

以下額外的語句或操作不允許在儲存函數中使用。它們允許在儲存程序中使用,但從儲存函數或觸發器中呼叫的儲存程序除外。例如,如果您在儲存程序中使用 FLUSH,則無法從儲存函數或觸發器呼叫該儲存程序。

  • 執行明確或隱含認可或回滾的語句。SQL 標準不要求支援這些語句,該標準規定每個 DBMS 廠商可以決定是否允許它們。

  • 傳回結果集的語句。這包括沒有 INTO var_list 子句的 SELECT 語句,以及其他語句,例如 SHOWEXPLAINCHECK TABLE。函數可以使用 SELECT ... INTO var_list 或使用游標和 FETCH 語句來處理結果集。請參閱第 15.2.13.1 節,「SELECT ... INTO 語句」,以及第 15.6.6 節,「游標」

  • FLUSH 語句。

  • 儲存函數不能以遞迴方式使用。

  • 儲存函數或觸發器不能修改呼叫該函數或觸發器的語句已在使用 (用於讀取或寫入) 的資料表。

  • 如果您在儲存函數中以不同的別名多次參照暫時資料表,即使這些參照發生在函數中的不同語句中,也會發生 Can't reopen table: 'tbl_name' 錯誤。

  • 呼叫儲存函數的 HANDLER ... READ 語句可能會導致複寫錯誤,因此不允許使用。

觸發器的限制

對於觸發器,以下額外限制適用

  • 觸發器不會由外鍵動作啟用。

  • 當使用以列為基礎的複寫時,複本上的觸發器不會由源頭的語句啟用。當使用以語句為基礎的複寫時,會啟用複本上的觸發器。如需更多資訊,請參閱第 19.5.1.37 節,「複寫和觸發器」

  • 觸發器中不允許使用 RETURN 語句,因為觸發器無法傳回值。若要立即結束觸發器,請使用 LEAVE 語句。

  • 不允許在 mysql 資料庫的資料表上使用觸發器。也不允許在 INFORMATION_SCHEMAperformance_schema 資料表上使用觸發器。這些資料表實際上是視圖,而視圖不允許使用觸發器。

  • 當基礎物件的中繼資料變更時,觸發器快取不會偵測到。如果觸發器使用資料表,而且資料表自觸發器載入快取後已變更,則觸發器會使用過時的中繼資料來操作。

儲存常式內的名稱衝突

相同的識別項可以用於常式參數、區域變數和資料表欄。此外,相同的區域變數名稱可以在巢狀區塊中使用。例如

CREATE PROCEDURE p (i INT)
BEGIN
  DECLARE i INT DEFAULT 0;
  SELECT i FROM t;
  BEGIN
    DECLARE i INT DEFAULT 1;
    SELECT i FROM t;
  END;
END;

在這種情況下,識別符號是含糊不清的,並適用以下優先順序規則

  • 區域變數的優先順序高於常式參數或表格欄位。

  • 常式參數的優先順序高於表格欄位。

  • 內部區塊中的區域變數的優先順序高於外部區塊中的區域變數。

變數優先於表格欄位的行為是非標準的。

複製考量

使用預存常式可能會導致複製問題。此問題在第 27.8 節「預存程式二進位日誌」中有更詳細的討論。

--replicate-wild-do-table=db_name.tbl_name選項適用於表格、檢視和觸發程序。它不適用於預存程序和函數,或事件。若要篩選對後者物件進行操作的陳述式,請使用一個或多個--replicate-*-db選項。

除錯考量

沒有預存常式除錯設施。

SQL:2003 標準中不支援的語法

MySQL 預存常式語法基於 SQL:2003 標準。目前不支援該標準中的以下項目

  • UNDO處理常式

  • FOR迴圈

預存常式並行考量

為了防止工作階段之間的互動問題,當客戶端發出陳述式時,伺服器會使用可用於執行陳述式的常式和觸發程序的快照。也就是說,伺服器會計算執行陳述式期間可能會使用的程序、函數和觸發程序清單,載入它們,然後繼續執行陳述式。在陳述式執行時,它看不到其他工作階段對常式所做的變更。

為了達到最大的並行性,預存函數應盡量減少其副作用;特別是,在預存函數內更新表格可能會減少對該表格的並行操作。預存函數會在執行前取得表格鎖定,以避免因陳述式的執行順序與它們在日誌中出現的順序不符而導致二進位日誌中的不一致。當使用基於陳述式的二進位日誌時,會記錄呼叫函數的陳述式,而不是在函數內執行的陳述式。因此,更新相同底層表格的預存函數不會並行執行。相反地,預存程序不會取得表格層級的鎖定。所有在預存程序中執行的陳述式都會寫入二進位日誌,即使是基於陳述式的二進位日誌也是如此。請參閱第 27.8 節「預存程式二進位日誌」

事件排程器限制

以下限制是事件排程器特有的

  • 事件名稱會以不區分大小寫的方式處理。例如,您不能在同一個資料庫中擁有兩個名稱為 anEventAnEvent 的事件。

  • 無法從預存程式中建立事件。如果事件名稱是以變數指定,則無法從預存程式中修改或刪除事件。事件也無法建立、修改或刪除預存常式或觸發程序。

  • LOCK TABLES陳述式生效時,禁止對事件使用 DDL 陳述式。

  • 使用 YEARQUARTERMONTHYEAR_MONTH 間隔的事件時序會以月來解析;使用任何其他間隔的事件時序則會以秒來解析。沒有辦法讓排定在同一秒發生的事件以給定的順序執行。此外,由於四捨五入、執行緒應用程式的本質,以及建立事件和發出其執行訊號需要非零的時間長度,事件可能會延遲 1 或 2 秒。但是,Information Schema EVENTS表格的LAST_EXECUTED欄位中顯示的時間,始終精確到實際事件執行時間的一秒之內。(另請參閱錯誤 #16522。)

  • 每次執行事件主體中包含的陳述式都會在新連線中發生;因此,這些陳述式對伺服器陳述式計數(例如Com_selectCom_insert,由SHOW STATUS顯示)在給定使用者工作階段中沒有影響。但是,此類計數在全域範圍內更新。(錯誤 #16422)

  • 事件不支援晚於 Unix Epoch 結束的時間;這大約是 2038 年初。事件排程器明確禁止此類日期。(錯誤 #16396)

  • 不支援在CREATE EVENTALTER EVENT陳述式的ON SCHEDULE子句中參考預存函數、可載入函數和表格。不允許這類參考。(如需更多資訊,請參閱錯誤 #22830。)

NDB Cluster 中的預存常式和觸發程序

雖然使用NDB儲存引擎的表格都支援預存程序、預存函數、觸發程序和排程事件,但您必須記住,這些不會在作為 Cluster SQL 節點的 MySQL 伺服器之間自動傳播。這是因為預存常式和觸發程序的定義會使用InnoDB表格儲存在mysql系統資料庫中的表格中,這些表格不會在叢集節點之間複製。

任何與 MySQL Cluster 表格互動的預存常式或觸發程序都必須重新建立,方法是在您希望使用預存常式或觸發程序的叢集中參與的每個 MySQL 伺服器上執行適當的CREATE PROCEDURECREATE FUNCTIONCREATE TRIGGER陳述式。同樣地,對現有預存常式或觸發程序的任何變更都必須在所有 Cluster SQL 節點上明確執行,方法是在每個存取叢集的 MySQL 伺服器上使用適當的ALTERDROP陳述式。

警告

請勿嘗試透過將任何 mysql 資料庫表格轉換為使用NDB儲存引擎來解決剛才描述的問題。不支援修改 mysql 資料庫中的系統表格,而且很可能會產生不良的結果。