對於用戶端在會話期間可能會多次執行的某些語句,伺服器會將該語句轉換為內部結構,並快取該結構以便在執行期間使用。快取讓伺服器能夠更有效率地執行,因為它可以避免在會話期間再次需要該語句時重新轉換的開銷。轉換和快取會針對以下語句發生
預處理語句,無論是透過 SQL 層級處理 (使用
PREPARE
語句) 還是使用二進位用戶端/伺服器協定處理 (使用mysql_stmt_prepare()
C API 函式)。max_prepared_stmt_count
系統變數控制伺服器快取的語句總數。(所有會話中預處理語句的數量總和。)儲存程式(儲存程序和函式、觸發程序和事件)。在這種情況下,伺服器會轉換並快取整個程式主體。
stored_program_cache
系統變數會指出伺服器每個會話快取的大約儲存程式數量。
伺服器會根據每個會話維護預處理語句和儲存程式的快取。為一個會話快取的語句無法被其他會話存取。當會話結束時,伺服器會捨棄為該會話快取的任何語句。
當伺服器使用快取的內部語句結構時,必須注意該結構不會過期。中繼資料變更可能會發生於語句使用的物件,導致目前的物件定義與內部語句結構中表示的定義不符。中繼資料變更會發生於 DDL 語句,例如建立、捨棄、變更、重新命名或截斷資料表的語句,或分析、最佳化或修復資料表的語句。資料表內容變更(例如,使用 INSERT
或 UPDATE
)不會變更中繼資料,SELECT
語句也不會變更中繼資料。
以下是一個問題的說明。假設用戶端準備了以下陳述式:
PREPARE s1 FROM 'SELECT * FROM t1';
內部結構中,SELECT *
會展開為表格中的欄位列表。如果表格中的欄位集合透過 ALTER TABLE
修改,已準備的陳述式就會過期。如果伺服器在用戶端下次執行 s1
時沒有偵測到此變更,已準備的陳述式會回傳不正確的結果。
為了避免已準備的陳述式所參照的表格或檢視表之元數據變更造成的問題,伺服器會偵測這些變更,並在下次執行時自動重新準備陳述式。也就是說,伺服器會重新剖析陳述式並重建內部結構。當參照的表格或檢視表從表格定義快取中清除時,也會發生重新剖析,這可能是為了讓出快取中新條目的空間而隱含地清除,或是因為 FLUSH TABLES
而明確地清除。
同樣地,如果儲存程序使用的物件發生變更,伺服器會重新剖析程式中受影響的陳述式。
伺服器也會偵測表達式中物件的元數據變更。這些可能會用於儲存程序特定的陳述式,例如 DECLARE CURSOR
,或流程控制陳述式,例如 IF
、CASE
和 RETURN
。
為了避免重新剖析整個儲存程序,伺服器僅在必要時重新剖析程式中受影響的陳述式或表達式。例如:
假設表格或檢視表的元數據已變更。程式中存取該表格或檢視表的
SELECT *
會發生重新剖析,但不會針對未存取該表格或檢視表的SELECT *
發生重新剖析。當陳述式受到影響時,伺服器會在可能的情況下僅部分重新剖析。請考慮以下
CASE
陳述式:CASE case_expr WHEN when_expr1 ... WHEN when_expr2 ... WHEN when_expr3 ... ... END CASE
如果元數據變更僅影響
WHEN
,則會重新剖析該表達式。when_expr3
case_expr
和其他WHEN
表達式則不會重新剖析。
重新剖析使用轉換為內部格式時有效的預設資料庫和 SQL 模式。
伺服器會嘗試重新剖析最多三次。如果所有嘗試都失敗,則會發生錯誤。
重新剖析是自動的,但就其發生的程度而言,會降低已準備陳述式和儲存程序的效能。
對於已準備的陳述式,Com_stmt_reprepare
狀態變數會追蹤重新準備的次數。