PostgreSQL PREPARE

2021-09-13 10:33 更新

PREPARE — 為執(zhí)行準(zhǔn)備一個(gè)語句

大綱

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

描述

PREPARE創(chuàng)建一個(gè)預(yù)備語句。預(yù)備語句是一種服務(wù)器端對(duì)象,它可以被用來優(yōu)化性能。當(dāng)PREPARE語句被執(zhí)行時(shí),指定的語句會(huì)被解析、分析并且重寫。當(dāng)后續(xù)發(fā)出一個(gè)EXECUTE命令時(shí),該預(yù)備語句會(huì)被規(guī)劃并且執(zhí)行。這種工作的劃分避免了重復(fù)性的解析分析工作,不過允許執(zhí)行計(jì)劃依賴所提供的特定參數(shù)值。

預(yù)備語句可以接受參數(shù):在執(zhí)行時(shí)會(huì)被替換到語句中的值。在創(chuàng)建預(yù)備語句時(shí),可以用位置引用參數(shù),如$1、$2等。也可以選擇性地指定參數(shù)數(shù)據(jù)類型的一個(gè)列表。當(dāng)一個(gè)參數(shù)的數(shù)據(jù)類型沒有被指定或者被聲明為unknown時(shí),其類型會(huì)從該參數(shù)第一次被引用的環(huán)境中推知(如果可能)。在執(zhí)行該語句時(shí),在EXECUTE語句中為這些參數(shù)指定實(shí)際值。更多有關(guān)于此的信息可參考 EXECUTE 。

預(yù)備語句只在當(dāng)前數(shù)據(jù)庫(kù)會(huì)話期間存在。當(dāng)會(huì)話結(jié)束時(shí),預(yù)備語句會(huì)消失,因此在重新使用之前必須重新建立它。這也意味著一個(gè)預(yù)備語句不能被多個(gè)數(shù)據(jù)庫(kù)客戶端同時(shí)使用。不過,每一個(gè)客戶端可以創(chuàng)建它們自己的預(yù)備語句來使用。預(yù)備語句可以用DEALLOCATE命令手工清除。

當(dāng)一個(gè)會(huì)話要執(zhí)行大量類似語句時(shí),預(yù)備語句可能會(huì)有最大性能優(yōu)勢(shì)。如果該語句很復(fù)雜(難于規(guī)劃或重寫),例如,如果查詢涉及很多表的連接或者要求應(yīng)用多個(gè)規(guī)則,性能差異將會(huì)特別明顯。如果語句相對(duì)比較容易規(guī)劃和重寫,但是執(zhí)行起來開銷相對(duì)較大,那么預(yù)備語句的性能優(yōu)勢(shì)就不那么顯著了。

參數(shù)

name

給這個(gè)特定預(yù)備語句的任意名稱。它在一個(gè)會(huì)話中必須唯一并且后續(xù)將被用來執(zhí)行或者清除一個(gè)之前準(zhǔn)備好的語句。

data_type

預(yù)備語句一個(gè)參數(shù)的數(shù)據(jù)類型。如果一個(gè)特定參數(shù)的數(shù)據(jù)類型沒有被指定或者被指定為unknown,將從該參數(shù)第一次被引用的環(huán)境中推得。要在預(yù)備語句本身中引用參數(shù),可以使用 $1、$2等。

statement

任何SELECT、INSERTUPDATE、DELETE或者VALUES語句。

注解

可以使用generic plancustom plan執(zhí)行已準(zhǔn)備好的語句。 通用計(jì)劃在所有執(zhí)行中都是相同的,而自定義計(jì)劃是為特定執(zhí)行所生成的,使用調(diào)用中給出的參數(shù)值。 使用通用計(jì)劃可以避免計(jì)劃開銷,但在某些情況下,自定義計(jì)劃的執(zhí)行效率要高得多,因?yàn)橐?guī)劃器可以利用參數(shù)值的知識(shí)。 (當(dāng)然,如果準(zhǔn)備好的語句沒有參數(shù),則這是沒有意義的,并且始終應(yīng)使用通用計(jì)劃。)

默認(rèn)情況下(也就是當(dāng) plan_cache_mode 設(shè)定為 auto時(shí)),對(duì)已經(jīng)準(zhǔn)備好的具有參數(shù)的語句,服務(wù)器將自動(dòng)選擇使用通用或自定義計(jì)劃。 當(dāng)前的規(guī)則是,前五次執(zhí)行都是使用自定義計(jì)劃完成的,并且計(jì)算這些計(jì)劃的平均估計(jì)成本。然后創(chuàng)建通用計(jì)劃,并將其估計(jì)成本與自定義計(jì)劃的平均成本相比較。 如果通用計(jì)劃的成本沒有比平均自定義計(jì)劃成本高太多,那么后續(xù)執(zhí)行將使用通用計(jì)劃,以使重復(fù)的再看起來更可取。

這種探索式方法可以重寫,強(qiáng)迫服務(wù)器使用通用或自定義計(jì)劃,通過將plan_cache_mode分別設(shè)置為force_generic_planforce_custom_plan 。 如果通用計(jì)劃的成本估計(jì)由于某種原因很不理想,則此設(shè)置主要很有用,盡管其實(shí)際成本遠(yuǎn)高于自定義計(jì)劃的實(shí)際成本,可以選擇此設(shè)置。

要檢查PostgreSQL為一個(gè)預(yù)備語句使用的查詢計(jì)劃,可以使用EXPLAIN,例如:

EXPLAIN EXECUTE name(parameter_values);

如果使用的是一個(gè)通用計(jì)劃,它將包含參數(shù)符號(hào)$n ,而一個(gè)定制計(jì)劃則會(huì)把提供的參數(shù)值替換進(jìn)去。

更多關(guān)于查詢規(guī)劃以及PostgreSQL為此所收集的統(tǒng)計(jì)信息的內(nèi)容,請(qǐng)見ANALYZE文檔。

盡管預(yù)備語句主要是為了避免重復(fù)對(duì)語句進(jìn)行解析分析以及規(guī)劃,但是只要上一次使用該預(yù)備語句后該語句中用到的數(shù)據(jù)庫(kù)對(duì)象發(fā)生了定義性(DDL)改變,PostgreSQL將會(huì)對(duì)該語句強(qiáng)制進(jìn)行重新分析和重新規(guī)劃。還有,如果search_path的值發(fā)生變化,也將使用新的search_path重新解析該語句(后一種行為是從 PostgreSQL9.3 開始的新行為)。這些規(guī)則讓預(yù)備語句的使用在語義上幾乎等效于反復(fù)提交相同的查詢文本,但是能在性能上獲利(如果沒有對(duì)象定義被改變,特別是如果最優(yōu)計(jì)劃保持不變時(shí))。該語義等價(jià)性不完美的一個(gè)例子是:如果語句用一個(gè)未限定的名稱引用表,并且之后在search_path中更靠前的模式中創(chuàng)建了一個(gè)新的同名表,則不會(huì)發(fā)生自動(dòng)的重解析,因?yàn)樵撜Z句使用的對(duì)象沒有被改變。不過,如果某些其他更改造成了重解析,后續(xù)使用中都會(huì)引用新表。

可以通過查詢pg_prepared_statements系統(tǒng)視圖來看到會(huì)話中所有可用的預(yù)備語句。

例子

為一個(gè)INSERT語句創(chuàng)建一個(gè)預(yù)備語句,然后執(zhí)行它:

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

為一個(gè)SELECT語句創(chuàng)建一個(gè)預(yù)備語句,然后執(zhí)行它:

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);

在這個(gè)示例中,第二個(gè)參數(shù)的數(shù)據(jù)類型沒有被指定,因此會(huì)從使用$2的環(huán)境中推知。

兼容性

SQL 標(biāo)準(zhǔn)包括一個(gè)PREPARE語句,但是它只用于嵌入式 SQL。這個(gè)版本的PREPARE語句也使用了一種有些不同的語法。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)