?
? ????? PHP ??? ???? ??? ?? ??
PREPARE name [ ( data_type [, ...] ) ] AS statement
PREPARE創(chuàng)建一個(gè)預(yù)備語句。一個(gè)預(yù)備語句是服務(wù)器端的對(duì)象,可以用于優(yōu)化性能。 在執(zhí)行PREPARE語句的時(shí)候,指定的查詢被分析、重寫、規(guī)劃。 當(dāng)隨后發(fā)出EXECUTE語句的時(shí)候,預(yù)備語句就只需要執(zhí)行了。 因此,分析、重寫、規(guī)劃階段都只執(zhí)行一次,而不是每次都要執(zhí)行一次。
預(yù)備語句可以接受參數(shù):在它執(zhí)行的時(shí)候替換到查詢中的數(shù)值。 可以在一個(gè)預(yù)備語句里按照位置來引用參數(shù),比如$1,$2等。 可以指定一個(gè)相應(yīng)的參數(shù)數(shù)據(jù)類型列表。 如果一個(gè)參數(shù)的數(shù)據(jù)類型沒有被指定或聲明為unknown, 那么其類型將根據(jù)該參數(shù)所使用的實(shí)際上下文環(huán)境進(jìn)行推測(如果有可能的話)。 當(dāng)執(zhí)行該語句的時(shí)候,將在EXECUTE語句中為這些參數(shù)指定實(shí)際值。 參見EXECUTE獲取更多信息。
預(yù)備語句只是在當(dāng)前數(shù)據(jù)庫會(huì)話的過程中存在。如果客戶端退出, 那么預(yù)備語句就會(huì)被遺忘,因此必須在被重新使用之前重新創(chuàng)建。 這也意味著一個(gè)預(yù)備語句不能被多個(gè)數(shù)據(jù)庫客戶端同時(shí)使用;但是, 每個(gè)客戶端可以創(chuàng)建它們自己的預(yù)備語句來使用。預(yù)備語句可以用 DEALLOCATE命令手工清除。
如果一個(gè)會(huì)話準(zhǔn)備用于執(zhí)行大量類似的查詢,那么預(yù)備語句可以獲得最大限度的性能優(yōu)勢。 如果查詢非常復(fù)雜,需要復(fù)雜的規(guī)劃或者重寫,那么性能差距將更加明顯。 比如,如果查詢設(shè)計(jì)許多表的連接,或者有多種規(guī)則要求應(yīng)用。如果查詢的規(guī)劃和重寫相對(duì)簡單, 而執(zhí)行起來開銷相當(dāng)大,那么預(yù)備語句的性能優(yōu)勢就不那么明顯。
給予這個(gè)特定的預(yù)備語句任意名字。它必須在一個(gè)會(huì)話中是唯一的,并且用于執(zhí)行或者刪除一個(gè)預(yù)備語句。
預(yù)備語句的某個(gè)參數(shù)的數(shù)據(jù)類型。如果某個(gè)參數(shù)的數(shù)據(jù)類型未指定或指定為unknown, 那么將根據(jù)該參數(shù)使用的上下文環(huán)境進(jìn)行推斷。可以使用 $1,$2等等在預(yù)備語句內(nèi)部引用這個(gè)參數(shù)。
SELECT,INSERT,UPDATE, DELETE或VALUES語句之一。
在一些情況下,PostgreSQL為一個(gè)預(yù)備語句生成的查詢 規(guī)劃可能還不如按照普通方法提交并執(zhí)行的查詢生成的規(guī)劃好。 這是因?yàn)樵摬樵冊诒灰?guī)劃的時(shí)候(也是優(yōu)化器判斷最優(yōu)查詢規(guī)劃的時(shí)候), 在查詢中聲明的任何參數(shù)的實(shí)際數(shù)值都還不可見。 PostgreSQL在表中收集數(shù)據(jù)分布的統(tǒng)計(jì),而且可以利用查 詢中的常量來猜測執(zhí)行查詢的可能結(jié)果。 因?yàn)檫@些數(shù)據(jù)在規(guī)劃的時(shí)候還是未知,所以,得到的規(guī)劃可能很差勁。 使用EXPLAIN查看PostgreSQL 為預(yù)備語句選取的查詢計(jì)劃。
有關(guān)查詢規(guī)劃和PostgreSQL為查詢優(yōu)化的目的收集統(tǒng)計(jì)的更多信息, 參閱ANALYZE文檔。
可以通過查詢pg_prepared_statements 系統(tǒng)試圖獲得某個(gè)會(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è)參數(shù)的數(shù)據(jù)類型并未指定。所以將從上下文環(huán)境推測$2的類型。
SQL標(biāo)準(zhǔn)包含一個(gè)PREPARE語句,但是它只用于嵌入式SQL。 PostgreSQL實(shí)現(xiàn)的PREPARE語句的語法也略有不同。