?
本文檔使用 PHP中文網(wǎng)手冊(cè) 發(fā)布
系統(tǒng)給 amcostestimate
函數(shù)一個(gè)WHERE子句的列表,這個(gè) WHERE 子
句列表是系統(tǒng)認(rèn)為可以被索引使用的東西。它必須返回訪問(wèn)該索引的開(kāi)銷(xiāo)估計(jì)值以
及 WHERE 子句的選擇性(也就是說(shuō),在索引掃描期間檢索的將被返回的數(shù)據(jù)行在父
表中所占據(jù)的比例)。對(duì)于簡(jiǎn)單的場(chǎng)合,幾乎開(kāi)銷(xiāo)估計(jì)器的所有工作都可以通過(guò)調(diào)
用優(yōu)化器里面的標(biāo)準(zhǔn)過(guò)程完成;有amcostestimate
這個(gè)函數(shù)的目的
是允許索引訪問(wèn)方法提供和索引類(lèi)型相關(guān)的知識(shí),這樣也許可以改進(jìn)標(biāo)準(zhǔn)的開(kāi)銷(xiāo)估計(jì)。
每個(gè) amcostestimate
函數(shù)都有下面這樣的簽名:
void amcostestimate (PlannerInfo *root, IndexOptInfo *index, List *indexQuals, RelOptInfo *outer_rel, Cost *indexStartupCost, Cost *indexTotalCost, Selectivity *indexSelectivity, double *indexCorrelation);
頭四個(gè)參數(shù)是輸入:
規(guī)劃器的有關(guān)正在被處理的查詢的信息。
在考慮使用的索引。
索引條件子句的列表(隱含是AND的);如果是NIL列表 (空列表)就表示沒(méi)有可用的條件。請(qǐng)注意這個(gè)列表包含表達(dá)式樹(shù),而不是 ScanKey(掃描鍵字)。
如果該索引可能要用于連接內(nèi)部掃描,那么這個(gè)將是規(guī)劃器關(guān)于連接 的外側(cè)信息,否則為NULL。當(dāng)不為NULL時(shí), 一些qual字句將會(huì)連接使用帶有這個(gè)rel的字句而不是簡(jiǎn)單的約束字句。 同樣,開(kāi)銷(xiāo)評(píng)估應(yīng)當(dāng)考慮到索引掃描將會(huì)為rel的每一行執(zhí)行一次。
后面四個(gè)參數(shù)是傳遞引用的輸出:
設(shè)置為索引啟動(dòng)處理的開(kāi)銷(xiāo)
設(shè)置為索引處理的總開(kāi)銷(xiāo)
設(shè)置為索引的選擇型
設(shè)置為索引掃描順序和下層的表的順序之間的相關(guān)有效性
請(qǐng)注意開(kāi)銷(xiāo)估計(jì)函數(shù)必須用C寫(xiě),而不能用SQL或者任何可用的存儲(chǔ)過(guò)程 語(yǔ)言,因?yàn)樗鼈儽仨氃L問(wèn)規(guī)劃器/優(yōu)化器的內(nèi)部數(shù)據(jù)結(jié)構(gòu)。
索引訪問(wèn)開(kāi)銷(xiāo)應(yīng)該以 src/backend/optimizer/path/costsize.c:使用的單位進(jìn)行計(jì)算:一個(gè)順序磁盤(pán)塊抓取開(kāi)銷(xiāo)是1.0 , 一個(gè)非順序抓取開(kāi)銷(xiāo)是seq_page_cost ,而處理一個(gè)索引行的 開(kāi)銷(xiāo)通常應(yīng)該是random_page_cost,而處理一個(gè)索引行的開(kāi)銷(xiāo) 通常應(yīng)該是cpu_index_tuple_cost。另外,在任何索引處理期 間調(diào)用的比較操作符,都應(yīng)該增加一個(gè)數(shù)量為cpu_operator_cost倍數(shù)的開(kāi)銷(xiāo)(特別是計(jì)算索引條件 indexQuals自己的時(shí)候)。
訪問(wèn)開(kāi)銷(xiāo)應(yīng)該包括所有與掃描索引本身相關(guān)的磁盤(pán)和CPU開(kāi)銷(xiāo),但是不包括檢 索或者處理索引標(biāo)識(shí)出來(lái)的父表的行的開(kāi)銷(xiāo)。
"啟動(dòng)開(kāi)銷(xiāo)""start-up cost"是總掃描開(kāi)銷(xiāo)中的這樣一部分: 在開(kāi)始抓取第一行之前,必須花掉的開(kāi)銷(xiāo)。對(duì)于大多數(shù)索引,這個(gè)可以是零,但 是那些啟動(dòng)開(kāi)銷(xiāo)很大的索引類(lèi)型可能不能把它設(shè)置為零。
indexSelectivity 應(yīng)該設(shè)置成在索引掃描期間,父表中的行被 選出出來(lái)的部分的百分比。在索引比較松散的情況下,這個(gè)值通常比實(shí)際通過(guò) 給出的查詢條件之行所占的百分比要高。
indexCorrelation應(yīng)該設(shè)置成索引順序和表順序之間的相關(guān)性 (范圍在 -1.0 到 1.0 之間)。這個(gè)數(shù)值用于調(diào)整從父表中抓取行的開(kāi)銷(xiāo)估計(jì)。
在連接情況下,返回的數(shù)值應(yīng)當(dāng)在每一次索引掃描之間平均。
開(kāi)銷(xiāo)估計(jì)
一個(gè)典型的開(kāi)銷(xiāo)估計(jì)器會(huì)像下面這樣進(jìn)行處理:
1.基于給出的查詢條件,估計(jì)并返回父表中將被訪問(wèn)的行的百分比。如果缺
乏索引類(lèi)型相關(guān)得知識(shí),那么使用標(biāo)準(zhǔn)的優(yōu)化器函數(shù) clauselist_selectivity()
:
*indexSelectivity = clauselist_selectivity(root, indexQuals, index->rel->relid, JOIN_INNER, NULL);
2.估計(jì)在掃描過(guò)程中將被訪問(wèn)的索引行數(shù)。對(duì)于許多索引類(lèi)型,這個(gè)等于 indexSelectivity乘以索引中的行數(shù),但是可能更多。 請(qǐng)注意,頁(yè)面中的索引尺寸和行數(shù)可以從IndexOptInfo 結(jié)構(gòu)中獲得。
3.估計(jì)在掃描中將檢索的索引頁(yè)面數(shù)量。這個(gè)可能就是 indexSelectivity乘以索引的總頁(yè)面數(shù)。
4.計(jì)算索引訪問(wèn)開(kāi)銷(xiāo)。一個(gè)通用的估計(jì)器可以這么干:
/* * Our generic assumption is that the index pages will be read * sequentially, so they cost seq_page_cost each, not random_page_cost. * Also, we charge for evaluation of the indexquals at each index row. * All the costs are assumed to be paid incrementally during the scan. */ cost_qual_eval(&index_qual_cost, indexQuals, root); *indexStartupCost = index_qual_cost.startup; *indexTotalCost = seq_page_cost * numIndexPages + (cpu_index_tuple_cost + index_qual_cost.per_tuple) * numIndexTuples;
不過(guò),上面沒(méi)有考慮在連接情況下的多次索引掃描中分期(amortization)開(kāi)銷(xiāo)。
Estimate the index correlation. For a simple ordered index on a single field, this can be retrieved from pg_statistic. If the correlation is not known, the conservative estimate is zero (no correlation).
5.估計(jì)索引的相關(guān)性。對(duì)于簡(jiǎn)單的在單個(gè)字段上的有序索引,這個(gè)值可以從 pg_statistic中檢索。如果相關(guān)性是未知,那么保守的估計(jì)是零(沒(méi)有相關(guān)性)。
開(kāi)銷(xiāo)估計(jì)器函數(shù)的例子可以在src/backend/utils/adt/ selfuncs.c 里面找到。