62.6. Функции оценки стоимости индекса#

62.6. Функции оценки стоимости индекса

62.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 больше единицы, возвращаемые числа должны быть средними значениями, ожидаемыми для одного сканирования индекса.

Оценка стоимости

Типичный оценщик стоимости будет действовать следующим образом:

  1. Оцените и верните долю строк родительской таблицы, которые будут посещены на основе заданных условий qual. В отсутствие каких-либо специфических для типа индекса знаний, используйте стандартную функцию оптимизатора clauselist_selectivity():

    *indexSelectivity = clauselist_selectivity(root, path->indexquals,
                                               path->indexinfo->rel->relid,
                                               JOIN_INNER, NULL);
    

  2. Оцените количество строк индекса, которые будут просмотрены во время сканирования. Для многих типов индексов это равно indexSelectivity умноженное на количество строк в индексе, но может быть больше. (Обратите внимание, что размер индекса в страницах и строках доступен из структуры path->indexinfo).

  3. Оцените количество страниц индекса, которые будут извлечены во время сканирования. Это может быть просто indexSelectivity раз размер индекса в страницах.

  4. Вычислите стоимость доступа к индексу. Обобщенный оценщик может сделать это:

    /*
     * 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;
    

    Однако вышеуказанное не учитывает амортизацию чтения индекса при повторных сканированиях индекса.

  5. Оцените корреляцию индекса. Для простого упорядоченного индекса на одном поле это можно получить из pg_statistic. Если корреляция неизвестна, консервативная оценка равна нулю (нет корреляции).

Примеры функций оценки стоимости можно найти в файле src/backend/utils/adt/selfuncs.c.