對於用戶端在會話期間可能會多次執行的某些語句,伺服器會將語句轉換為內部結構,並快取該結構以供執行期間使用。快取可讓伺服器更有效率地執行,因為它可以避免在會話期間再次需要該語句時重新轉換的額外負荷。轉換和快取會發生在這些語句中
預處理語句,包括在 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
狀態變數會追蹤重新準備的次數。