61.6. Функции оценки стоимости индекса#
61.6. Функции оценки стоимости индекса #
Функция 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. Обратите внимание, что оценки стоимости все равно должны быть только для одного сканирования; большее значение
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
. Кроме того, за любые операторы сравнения, вызываемые во время обработки индекса (особенно при оценке самих indexquals), должна взыматься соответствующая кратность cpu_operator_cost
.
Стоимость доступа должна включать все затраты на диск и ЦП, связанные с сканированием самого индекса, но не затраты на извлечение или обработку строк родительской таблицы, которые идентифицируются индексом.
Стоимость запуска - это часть общей стоимости сканирования, которую необходимо затратить перед тем, как мы сможем начать извлекать первую строку. Для большинства индексов это можно считать равным нулю, но тип индекса с высокой стоимостью запуска может захотеть установить его ненулевым.
Параметр indexSelectivity
должен быть установлен на оценочную долю строк родительской таблицы, которые будут извлечены во время сканирования индекса. В случае потери запроса, это обычно будет выше доли строк, которые фактически проходят заданные условия качества.
Параметр indexCorrelation
должен быть установлен на корреляцию (в диапазоне от -1.0 до 1.0) между порядком индекса и порядком таблицы. Это используется для корректировки оценки стоимости извлечения строк из родительской таблицы.
Параметр indexPages
должен быть установлен на количество листовых страниц.
Это используется для оценки количества рабочих процессов для параллельного сканирования индекса.
Когда loop_count
больше единицы, возвращаемые числа должны быть средними значениями, ожидаемыми для одного сканирования индекса.
Оценка стоимости
Типичный оценщик стоимости будет действовать следующим образом:
Оцените и верните долю строк родительской таблицы, которые будут посещены на основе заданных условий qual. В отсутствие каких-либо специфических для типа индекса знаний, используйте стандартную функцию оптимизатора
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
.