Функции оценки стоимости индекса
Функции amcostestimate
предоставляется информация, описывающая возможное сканирование индекса, включая списки предложений WHERE и ORDER BY, которые были определены как пригодные для использования с индексом. Она должна вернуть оценки стоимости доступа к индексу и селективности предложений WHERE (то есть долю строк родительской таблицы, которые будут получены при сканировании индекса). Для простых случаев почти вся работа оценщика стоимости может быть выполнена вызовом стандартных процедур в оптимизаторе; смысл наличия функции amcostestimate заключается в том, чтобы позволить методам доступа к индексу предоставлять знания, специфичные для типа индекса, в случае, если можно улучшить стандартные оценки.
Каждая функция amcostestimate
должна иметь сигнатуру:
void
amcostestimate (PlannerInfo *root,
IndexPath *path,
double loop_count,
Cost *indexStartupCost,
Cost *indexTotalCost,
Selectivity *indexSelectivity,
double *indexCorrelation,
double *indexPages);
Первые три параметра являются входными:
root
Информация планировщика об обрабатываемом запросе.
path
Рассматриваемый путь доступа к индексу. Все поля, кроме значений стоимости и селективности, действительны.
loop_count
Количество повторений сканирования индекса, которое должно учитываться в оценке стоимости. Обычно это значение больше единицы, когда рассматривается параметризованное сканирование для использования внутри nestloop join. Обратите внимание, что оценка стоимости все равно должна быть рассчитана только на одно сканирование; большее значение loop_count означает, что может быть уместно разрешить некоторые эффекты кэширования при нескольких сканированиях.
Последние пять параметров — указатели на переменные для выходных значений:
indexStartupCost
Стоимость выполнения запуска индекса.
indexTotalCost
Общая стоимость использования индекса.
indexSelectivity
Избирательность индекса.
indexCorrelation
Коэффициент корреляции между порядком сканирования индекса и порядком базовой таблицы.
indexPages
Число страниц индексного листа.
Обратите внимание, что функции оценки стоимости должны быть написаны на языке C, а не на SQL или любом другом доступном процедурном языке, поскольку они должны обращаться к внутренним структурам данных планировщика/оптимизатора.
Стоимость доступа к индексу должна вычисляться с помощью параметров, используемых в src/backend/optimizer/path/costsize.c
: последовательная выборка дисковых блоков имеет стоимость seq_page_cost
, не последовательная выборка имеет стоимость random_page_cost
, а стоимость обработки одной индексной строки обычно принимается за cpu_index_tuple_cost
. Кроме того, соответствующее кратное значение cpu_operator_cost
должно взиматься за любые операторы сравнения, вызываемые во время обработки индекса (особенно за вычисление собственно условий индекса).
Стоимость доступа должна включать все дисковые и процессорные затраты, связанные со сканированием самого индекса, но не затраты на получение или обработку строк родительской таблицы, которые идентифицируются индексом.
«Начальная стоимость» – эт о часть общей стоимости сканирования, которая должна быть потрачена до того, как мы начнем получать первый ряд. Для большинства индексов этот параметр можно принять за ноль, но для индексов с высокой начальной стоимостью, возможно, потребуется установить ненулевое значение.
Значение indexSelectivity должно соответствовать предполагаемой доле строк родительской таблицы, которые будут получены при сканировании индекса. В случае запроса с потерями это значение обычно будет выше, чем доля строк, которые действительно удовлетворяют заданным условиям качества.
IndexCorrelation должен быть установлен как корреляция (в диапазоне от -1.0 до 1.0) между порядком индекса и порядком таблицы. Это используется для корректировки оценки стоимости извлечения строк из родительской таблицы.
IndexPages должен быть установлен на количество страниц листа. Это используется для оценки количества рабочих для параллельного сканирования индекса.
Если loop_count больше единицы, то возвращаемые числа должны быть средними, ожидаемыми для одного сканирования индекса.
Оценка стоимости
Типичная оценка стоимости выглядит следующим образом:
-
Оцените и верните долю строк родительских таблиц, которые будут посещаться на основе заданных условий качества. При отсутствии знаний, специфичных для типа индекса, используйте стандартную функцию оптимизатора
clauselist_selectivity()
:*indexSelectivity = clauselist_selectivity(root, path->indexquals,
path->indexinfo->rel->relid,
JOIN_INNER, NULL); -
Оцените количество строк индекса, которые будут посещаться во время сканирования. Для многих типов индекса это то же самое, что и
indexSelectivity
, умноженное на количество строк в индексе, но оно может быть больше (Обратите внимание, что размер индекса в страницах и строках доступен черезpath->indexinfo
.). -
Оцените количество индексных страниц, которые будут получены во время сканирования. Это может быть просто
indexSelectivity
, умноженное на размер индекса на страницах. -
Рассчитайте стоимость доступа к индексу. Общий оценщик может сделать следующее:
/*
* 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, path->indexquals, root);
*indexStartupCost = index_qual_cost.startup;
*indexTotalCost = seq_page_cost * numIndexPages +
(cpu_index_tuple_cost + index_qual_cost.per_tuple) * numIndexTuples;Однако вышеописанное не учитывает амортизацию чтения индексов при многократном сканировании индексов.
-
Оцените корреляцию индекса. Для простого упорядоченного индекса по одному полю это можно получить из
pg_statistic
. Е сли корреляция неизвестна, консервативная оценка равна нулю (корреляция отсутствует).
Примеры функций оценки стоимости можно найти в src/backend/utils/adt/selfuncs.c
.