支援的版本:目前 (17) / 16 / 15 / 14 / 13
開發版本:devel
不支援的版本:12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3

PREPARE

PREPARE — 準備一個陳述式以供執行

概要

PREPARE name [ ( data_type [, ...] ) ] AS statement

描述

PREPARE 建立一個預先準備的陳述式。預先準備的陳述式是一個伺服器端的物件,可以用來最佳化效能。當 PREPARE 陳述式被執行時,指定的陳述式會被解析、分析和重寫。當隨後發出 EXECUTE 指令時,預先準備的陳述式會被規劃並執行。這種分工避免了重複的解析分析工作,同時允許執行計畫依賴於提供的特定參數值。

預先準備的陳述式可以接受參數:在執行陳述式時會被替換到陳述式中的值。在建立預先準備的陳述式時,使用 $1$2 等依照位置來參照參數。可以選擇性地指定對應的參數資料類型清單。當參數的資料類型未指定或宣告為 unknown 時,類型會從參數第一次被參照的上下文中推斷出來(如果可能的話)。在執行陳述式時,在 EXECUTE 陳述式中指定這些參數的實際值。有關更多資訊,請參閱 EXECUTE

預先準備的陳述式僅在目前資料庫連線期間有效。當連線結束時,預先準備的陳述式會被遺忘,因此必須重新建立才能再次使用。這也意味著單一預先準備的陳述式不能被多個同時存在的資料庫客戶端使用;但是,每個客戶端都可以建立自己的預先準備的陳述式來使用。預先準備的陳述式可以使用 DEALLOCATE 指令手動清除。

當使用單一連線執行大量相似的陳述式時,預先準備的陳述式可能具有最大的效能優勢。如果陳述式的規劃或重寫很複雜,效能差異將尤其顯著,例如,如果查詢涉及多個資料表的聯結或需要應用多個規則。如果陳述式的規劃和重寫相對簡單,但執行成本相對較高,則預先準備的陳述式的效能優勢將不太明顯。

參數

name

賦予這個特定預先準備陳述式的任意名稱。它在單一連線中必須是唯一的,並且隨後用於執行或釋放先前準備的陳述式。

data_type

預先準備陳述式的參數的資料類型。如果特定參數的資料類型未指定或指定為 unknown,則會從參數第一次被參照的上下文中推斷出來。要在預先準備的陳述式本身中參照參數,請使用 $1$2 等。

statement

任何 SELECTINSERTUPDATEDELETEMERGEVALUES 陳述式。

注意

預先準備的陳述式可以使用通用計畫自訂計畫來執行。 通用計畫在所有執行中都是相同的,而自訂計畫是針對使用該呼叫中給定的參數值的特定執行而產生的。 使用通用計畫可避免計畫開銷,但在某些情況下,由於計畫器可以利用參數值的知識,因此自訂計畫的執行效率會更高。(當然,如果預先準備的陳述式沒有參數,那麼這就沒有意義,並且總是使用通用計畫。)

預設情況下(也就是說,當 plan_cache_mode 設定為 auto 時),伺服器會自動選擇對於具有參數的預先準備陳述式使用通用計畫還是自訂計畫。 目前的規則是,前五次執行使用自訂計畫,並計算這些計畫的平均估計成本。 然後建立通用計畫,並將其估計成本與平均自訂計畫成本進行比較。 如果通用計畫的成本並未比平均自訂計畫成本高出太多,以至於重複重新計畫似乎更可取,則後續執行會使用通用計畫。

此啟發式方法可以被覆寫,透過將 plan_cache_mode 分別設定為 force_generic_planforce_custom_plan,強制伺服器使用通用計畫或自訂計畫。 如果通用計畫的成本估計由於某種原因嚴重偏離,允許選擇它,即使其實際成本遠高於自訂計畫,則此設定主要有用。

要檢查 PostgreSQL 正在用於預先準備陳述式的查詢計畫,請使用 EXPLAIN,例如

EXPLAIN EXECUTE name(parameter_values);

如果正在使用通用計畫,它將包含參數符號 $n,而自訂計畫將會把提供的參數值替換到其中。

關於查詢規劃以及 PostgreSQL 為此目的所收集的統計資訊,請參閱 ANALYZE 文件。

雖然預備語句的主要目的是避免重複的語法分析和語句規劃,但只要語句中使用的資料庫物件自上次使用預備語句以來,經歷了定義上的 (DDL) 變更,或者其規劃器的統計資訊已更新,PostgreSQL 就會強制在使用預備語句之前重新分析和重新規劃該語句。此外,如果 search_path 的值在每次使用之間發生變化,則該語句將使用新的 search_path 重新解析。(後者行為是 PostgreSQL 9.3 的新特性。) 這些規則使得預備語句在語義上幾乎等同於一次又一次地重新提交相同的查詢文字,但如果沒有物件定義被更改,則可以提高效能,尤其是當最佳規劃在多次使用中保持不變時。一個語義等價並不完美的例子是,如果語句通過未限定的名稱引用一個資料表,然後在 search_path 中較早出現的綱要中建立一個同名的新資料表,則不會發生自動重新解析,因為語句中使用的物件沒有更改。但是,如果某些其他更改強制重新解析,則在後續使用中將引用新資料表。

您可以透過查詢 pg_prepared_statements 系統檢視表,查看會話中所有可用的預備語句。

範例

INSERT 語句建立預備語句,然後執行它

PREPARE fooplan (int, text, bool, numeric) AS
    INSERT INTO foo VALUES($1, $2, $3, $4);
EXECUTE fooplan(1, 'Hunter Valley', 't', 200.00);

SELECT 語句建立預備語句,然後執行它

PREPARE usrrptplan (int) AS
    SELECT * FROM users u, logs l WHERE u.usrid=$1 AND u.usrid=l.usrid
    AND l.date = $2;
EXECUTE usrrptplan(1, current_date);

在這個範例中,沒有指定第二個參數的資料類型,因此它是從 $2 的使用上下文中推斷出來的。

相容性

SQL 標準包含一個 PREPARE 語句,但它僅用於嵌入式 SQL。這個版本的 PREPARE 語句也使用稍微不同的語法。

另請參閱

DEALLOCATE, EXECUTE

提交更正

如果您在文件中發現任何不正確、與您使用特定功能的經驗不符或需要進一步澄清的地方,請使用此表單來回報文件問題。