這些限制適用於第 27 章,儲存物件中描述的功能。
此處提到的一些限制適用於所有儲存常式;也就是說,同時適用於儲存程序和儲存函數。還有一些特定於儲存函數但不適用於儲存程序的限制。
儲存函數的限制也適用於觸發器。還有一些特定於觸發器的限制。
儲存程序的限制也適用於事件排程器事件定義的DO
子句。還有一些特定於事件的限制。
儲存常式不能包含任意 SQL 語句。不允許以下語句
鎖定語句
LOCK TABLES
和UNLOCK TABLES
。SQL 預備語句(
PREPARE
、EXECUTE
、DEALLOCATE PREPARE
)可以在儲存程序中使用,但不能在儲存函數或觸發器中使用。因此,儲存函數和觸發器不能使用動態 SQL(將語句構造成字串然後執行它們)。一般來說,SQL 預備語句中不允許的語句在儲存程式中也不允許。有關作為預備語句支援的語句列表,請參閱第 15.5 節, “預備語句”。例外情況是
SIGNAL
、RESIGNAL
和GET DIAGNOSTICS
,它們不允許作為預備語句,但在儲存程式中允許。由於局部變數僅在儲存程式執行期間有效,因此在儲存程式中建立的預備語句中不允許對它們的引用。預備語句的作用域是當前會話,而不是儲存程式,因此該語句可以在程式結束後執行,此時變數將不再有效。例如,
SELECT ... INTO
不能用作預備語句。此限制也適用於儲存程序和函數參數。請參閱第 15.5.1 節, “PREPARE 語句”。local_var
在所有儲存程式(儲存程序和函數、觸發器和事件)中,解析器將
BEGIN [WORK]
視為BEGIN ... END
區塊的開始。若要在此內容中開始交易,請改用START TRANSACTION
。
以下額外語句或操作在儲存函數中不允許。它們在儲存程序中允許,但從儲存函數或觸發器內調用的儲存程序除外。例如,如果您在儲存程序中使用 FLUSH
,則該儲存程序不能從儲存函數或觸發器中調用。
執行明確或隱含 commit 或 rollback 的語句。SQL 標準不要求支援這些語句,該標準規定每個 DBMS 供應商可以決定是否允許它們。
傳回結果集的語句。這包括沒有
INTO
子句的var_list
SELECT
語句以及其他語句,如SHOW
、EXPLAIN
和CHECK 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.36 節, “複製和觸發器”。
不允許在
mysql
資料庫中的資料表上建立觸發器。也不允許在INFORMATION_SCHEMA
或performance_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.7 節「儲存程式二進位記錄」中進一步討論。
--replicate-wild-do-table=
選項適用於資料表、視圖和觸發器。它不適用於儲存程序和函數,或事件。若要篩選對後者物件進行運作的敘述,請使用一或多個 db_name.tbl_name
--replicate-*-db
選項。
為了防止工作階段之間的互動問題,當用戶端發出敘述時,伺服器會使用可用於執行該敘述的常式和觸發器的快照。也就是說,伺服器會計算可能在敘述執行期間使用的程序、函數和觸發器的清單、載入它們,然後繼續執行該敘述。在敘述執行時,它看不到其他工作階段對常式所做的變更。
為了達到最大的並行性,儲存函數應將其副作用降至最低;特別是,在儲存函數內更新資料表可能會減少對該資料表的並行運作。儲存函數會在執行之前取得資料表鎖定,以避免因敘述的執行順序與它們在記錄中出現的順序不符而導致二進位記錄不一致。當使用以敘述為基礎的二進位記錄時,會記錄呼叫函數的敘述,而不是在函數內執行的敘述。因此,更新相同基礎資料表的儲存函數不會平行執行。相較之下,儲存程序不會取得資料表層級的鎖定。在儲存程序內執行的所有敘述都會寫入二進位記錄,即使是針對以敘述為基礎的二進位記錄。請參閱 第 27.7 節「儲存程式二進位記錄」。
下列限制是事件排程器特有的:
事件名稱會以不區分大小寫的方式處理。例如,您不能在同一個資料庫中擁有兩個名稱分別為
anEvent
和AnEvent
的事件。不能從儲存程式中建立事件。如果事件名稱是以變數指定,則不能從儲存程式中變更或刪除事件。事件也不能建立、變更或刪除儲存常式或觸發器。
當
LOCK TABLES
敘述生效時,禁止對事件使用 DDL 敘述。使用間隔
YEAR
、QUARTER
、MONTH
和YEAR_MONTH
的事件計時會以月為單位解析;使用任何其他間隔的事件計時會以秒為單位解析。無法讓預定在同一秒發生的事件以指定的順序執行。此外,由於四捨五入、執行緒應用程式的性質,以及建立事件和發出執行訊號需要非零的時間長度,事件可能會延遲最多 1 或 2 秒。但是,Information SchemaEVENTS
資料表的LAST_EXECUTED
欄位中顯示的時間,其精確度始終在實際事件執行時間的一秒內。(另請參閱錯誤 #16522)。每次執行事件主體中包含的敘述都會在新連線中進行;因此,這些敘述在伺服器的敘述計數 (例如
SHOW STATUS
所顯示的Com_select
和Com_insert
) 上,對給定的使用者工作階段沒有任何作用。不過,這些計數在全域範圍中會更新。(錯誤 #16422)事件不支援晚於 Unix Epoch 結束的時間;這大約是 2038 年初。事件排程器明確不允許此類日期。(錯誤 #16396)
不支援在
CREATE EVENT
和ALTER EVENT
敘述的ON SCHEDULE
子句中參考儲存函數、可載入函數和資料表。不允許這些參考。(如需詳細資訊,請參閱錯誤 #22830)。
雖然使用 NDB
儲存引擎的資料表都支援儲存程序、儲存函數、觸發器和排程事件,但您必須記住,這些不會在充當叢集 SQL 節點的 MySQL 伺服器之間自動傳播。這是因為儲存常式和觸發器定義會使用 InnoDB
資料表儲存在 mysql
系統資料庫中的資料表中,這些資料表不會在叢集節點之間複製。
任何與 MySQL 叢集資料表互動的儲存常式或觸發器,都必須在叢集中您想要使用該儲存常式或觸發器的每個 MySQL 伺服器上執行適當的 CREATE PROCEDURE
、CREATE FUNCTION
或 CREATE TRIGGER
敘述來重新建立。同樣地,對現有儲存常式或觸發器進行的任何變更,都必須在所有叢集 SQL 節點上明確執行,並在存取叢集的每個 MySQL 伺服器上使用適當的 ALTER
或 DROP
敘述。
請不要嘗試透過將任何 mysql
資料庫資料表轉換為使用 NDB
儲存引擎來規避剛才描述的問題。不支援變更 mysql
資料庫中的系統資料表,而且非常有可能產生不良的結果。