18.7. Планирование запросов#
18.7. Планирование запросов #
18.7.1. Конфигурация метода планировщика #
Эти параметры конфигурации предоставляют грубый метод влияния на выбор планов запросов оптимизатором запросов. Если выбранный оптимизатором по умолчанию план для конкретного запроса не является оптимальным, временным решением является использование одного из этих параметров конфигурации для принудительного выбора оптимизатором другого плана.
Лучшие способы улучшения качества выбранных оптимизатором планов включают настройку констант стоимости планировщика (см. Раздел 18.7.2), выполнение ANALYZE
вручную, увеличение значения параметра конфигурации default_statistics_target, а также увеличение объема собираемой статистики для конкретных столбцов с помощью ALTER TABLE SET STATISTICS
.
enable_async_append
(boolean
) #Включает или отключает использование асинхронно-осведомленных типов планов при планировании запросов. По умолчанию установлено значение
on
.enable_bitmapscan
(boolean
) #Включает или отключает использование планировщиком запросов планов с использованием сканирования по битовым картам. По умолчанию установлено значение
on
.enable_gathermerge
(boolean
) #Включает или отключает использование планировщиком запросов типов планов gather merge. По умолчанию установлено значение
on
.enable_group_by_reordering
(boolean
) #Включает или отключает переупорядочивание ключей в
GROUP BY
предложении. По умолчаниюon
.enable_hashagg
(boolean
) #Включает или отключает использование планировщиком запросов типов планов агрегации с хешированием. По умолчанию установлено значение
on
.enable_hashjoin
(boolean
) #Включает или отключает использование планировщиком запросов планов типа hash-join. По умолчанию установлено значение
on
.enable_incremental_sort
(boolean
) #Включает или отключает использование инкрементальных сортировочных шагов планировщиком запросов. По умолчанию установлено значение
on
.enable_indexscan
(boolean
) #Включает или отключает использование планировщиком запросов типов планов index-scan и index-only-scan. По умолчанию установлено значение
on
. Также смотрите enable_indexonlyscan.enable_indexonlyscan
(boolean
) #Включает или отключает использование планировщиком запросов типов планов с индексным сканированием только по индексам (см. Раздел 11.9). По умолчанию
включено
. Настройка enable_indexscan также должна быть включена, чтобы планировщик запросов рассматривал индексное сканирование только по индексам.enable_material
(boolean
) #Включает или отключает использование материализации планировщиком запросов. Полностью подавить материализацию невозможно, но отключение этой переменной предотвращает планировщик от вставки узлов материализации, кроме случаев, когда это необходимо для корректности. Значение по умолчанию -
on
.enable_memoize
(boolean
) #Включает или отключает использование планировщиком запросов планов с мемоизацией для кеширования результатов от параметризованных сканирований внутри соединений вложенным циклом. Этот тип плана позволяет пропустить сканирования в основных планах, когда результаты для текущих параметров уже находятся в кеше. Реже запрашиваемые результаты могут быть удалены из кеша, когда требуется больше места для новых записей. По умолчанию включено
on
.enable_mergejoin
(boolean
) #Включает или отключает использование планировщиком запросов планов слияния соединений. По умолчанию установлено значение
on
.enable_nestloop
(boolean
) #Включает или отключает использование планировщиком запросов планов соединения вложенным циклом. Полностью подавить использование вложенных циклов соединений невозможно, но отключение этой переменной отговаривает планировщик от использования их, если доступны другие методы. Значение по умолчанию -
on
.enable_parallel_append
(boolean
) #Включает или отключает использование планировщиком запросов типов планов с возможностью параллельного выполнения. По умолчанию установлено значение
on
.enable_parallel_hash
(boolean
) #Включает или отключает использование планировщиком запросов планов типа hash-join с параллельным хешированием. Не имеет эффекта, если планы hash-join также не включены. По умолчанию установлено значение
on
.enable_partition_pruning
(boolean
) #Включает или отключает возможность планировщика запросов удалять секции секционированной таблицы из планов запросов. Это также контролирует возможность планировщика генерировать планы запросов, которые позволяют исполнителю запросов удалять (игнорировать) секции во время выполнения запроса. По умолчанию включено (
on
). См. Раздел 5.11.4 для получения дополнительной информации.enable_partitionwise_join
(boolean
) #Включает или отключает использование планировщиком запросов соединения по секциям, что позволяет выполнять соединение между секционированными таблицами, соединяя соответствующие секции. Соединение по секциям в настоящее время применяется только когда условия соединения включают все ключи секций, которые должны быть одного и того же типа данных и иметь один-к-одному соответствующие наборы дочерних секций. При включении этой настройки количество узлов, использование памяти которых ограничено
work_mem
, появляющихся в итоговом плане, может увеличиваться линейно в зависимости от количества сканируемых секций. Это может привести к значительному увеличению общего потребления памяти во время выполнения запроса. Планирование запроса также становится значительно более дорогим с точки зрения памяти и ЦП. Значение по умолчанию —off
.enable_partitionwise_aggregate
(boolean
) #Включает или отключает использование планировщиком запросов группировки или агрегации по секциям, что позволяет выполнять группировку или агрегацию на секционированных таблицах отдельно для каждой секции. Если предложение
GROUP BY
не включает ключи секций, только частичная агрегация может быть выполнена на основе каждой секции, а финализация должна быть выполнена позже. При включении этой настройки количество узлов, использование памяти которых ограниченоwork_mem
, появляющихся в окончательном плане, может увеличиваться линейно в зависимости от количества сканируемых секций. Это может привести к значительному увеличению общего потребления памяти во время выполнения запроса. Планирование запроса также становится значительно более затратным с точки зрения использования памяти и ресурсов процессора. Значение по умолчанию —off
.enable_presorted_aggregate
(boolean
) #Управляет тем, будет ли планировщик запросов создавать план, который предоставит строки, отсортированные в порядке, требуемом для
ORDER BY
/DISTINCT
агрегатных функций запроса. Когда отключено, планировщик запросов создаст план, который всегда потребует от исполнителя выполнения сортировки перед выполнением агрегации каждой агрегатной функции, содержащей предложениеORDER BY
илиDISTINCT
. Когда включено, планировщик будет пытаться создать более эффективный план, который предоставляет входные данные для агрегатных функций, отсортированные в порядке, необходимом для агрегации. Значение по умолчанию —on
.enable_self_join_removal
(boolean
) #Включает или отключает оптимизацию планировщика запросов, которая анализирует дерево запроса и заменяет самосоединения семантически эквивалентными одиночными сканированиями. Учитываются только обычные таблицы. По умолчанию
on
.enable_seqscan
(boolean
) #Включает или отключает использование планировщиком запросов планов с последовательным сканированием. Полностью подавить последовательные сканирования невозможно, но отключение этой переменной отговаривает планировщик от использования их, если доступны другие методы. Значение по умолчанию -
on
.enable_sort
(boolean
) #Включает или отключает использование явных сортировок планировщиком запросов. Полностью подавить явные сортировки невозможно, но отключение этой переменной отговаривает планировщик от их использования, если доступны другие методы. Значение по умолчанию -
on
.enable_tidscan
(boolean
) #Включает или отключает использование планировщиком запросов типов планов сканирования TID. По умолчанию установлено значение
on
.
18.7.2. Константы стоимости планировщика #
Переменные стоимости , описанные в этом разделе, измеряются на произвольной шкале. Важны только их относительные значения, поэтому масштабирование всех переменных вверх или вниз на одинаковый коэффициент не приведет к изменению выбора планировщика. По умолчанию эти переменные стоимости основаны на стоимости последовательного извлечения страниц; то есть, переменная seq_page_cost
обычно устанавливается в 1.0
, и другие переменные стоимости устанавливаются относительно этого значения. Однако вы можете использовать другой масштаб, если предпочитаете, например, фактическое время выполнения в миллисекундах на конкретной машине.
Примечание
К сожалению, нет четко определенного метода для определения идеальных значений для переменных стоимости. Лучше всего рассматривать их как средние значения по всему набору запросов, которые будет получать конкретная установка. Это означает, что изменение их на основе всего нескольких экспериментов очень рискованно.
seq_page_cost
(floating point
) #Устанавливает оценку стоимости извлечения страницы диска планировщиком, которая является частью последовательного извлечения. По умолчанию значение равно 1.0. Это значение может быть переопределено для таблиц и индексов в определенном табличном пространстве путем установки параметра табличного пространства с тем же именем (см. ALTER TABLESPACE).
random_page_cost
(floating point
) #Устанавливает оценку стоимости страницы диска, которая не выбирается последовательно, для планировщика. По умолчанию значение равно 4.0. Это значение может быть переопределено для таблиц и индексов в определенном табличном пространстве путем установки параметра табличного пространства с тем же именем (см. ALTER TABLESPACE).
Уменьшение этого значения относительно
seq_page_cost
заставит систему предпочитать сканирование индекса; увеличение этого значения сделает сканирование индекса относительно более дорогостоящим. Вы можете одновременно повышать или понижать оба значения, чтобы изменить важность затрат на дисковый ввод-вывод относительно затрат на ЦП, которые описываются следующими параметрами.Доступ к случайному доступу к механическому дисковому хранилищу обычно намного дороже, чем последовательный доступ в четыре раза. Однако используется более низкое значение по умолчанию (4.0), потому что предполагается, что большинство случайных обращений к диску, таких как индексированные чтения, находятся в кеше. Значение по умолчанию можно рассматривать как моделирование случайного доступа, в 40 раз медленнее последовательного, ожидая, что 90% случайных чтений будут кешированы.
Если вы считаете, что предположение о 90% кеш-попадании неверно для вашей рабочей нагрузки, вы можете увеличить random_page_cost, чтобы лучше отразить реальную стоимость случайного чтения с диска. Соответственно, если ваши данные скорее всего полностью находятся в кеше, например, когда размер базы данных меньше общей памяти сервера, уменьшение random_page_cost может быть уместным. Хранилище с низкой стоимостью случайного чтения по сравнению с последовательным, например, твердотельные накопители, также могут быть лучше моделированы с использованием более низкого значения для random_page_cost, например,
1.1
.Подсказка
Хотя система позволяет установить значение
random_page_cost
меньше значенияseq_page_cost
, физически это не имеет смысла. Однако, установка их равными имеет смысл, если база данных полностью находится в оперативной памяти, так как в этом случае нет штрафа за обращение к страницам вне последовательности. Кроме того, в случае с сильно кешированной базой данных следует уменьшить оба значения относительно параметров ЦП, так как стоимость получения страницы, уже находящейся в оперативной памяти, гораздо меньше, чем обычно.cpu_tuple_cost
(floating point
) #Устанавливает оценку стоимости обработки каждой строки во время запроса планировщика. По умолчанию значение равно 0.01.
cpu_index_tuple_cost
(floating point
) #Устанавливает оценку стоимости обработки каждой записи индекса во время сканирования индекса. По умолчанию значение равно 0.005.
cpu_operator_cost
(floating point
) #Устанавливает оценку стоимости обработки каждого оператора или функции, выполняемых во время запроса планировщиком. По умолчанию значение равно 0.0025.
parallel_setup_cost
(floating point
) #Устанавливает оценку стоимости запуска параллельных рабочих процессов планировщика. По умолчанию значение равно 1000.
parallel_tuple_cost
(floating point
) #Устанавливает оценку стоимости передачи одной кортежа из параллельного рабочего процесса в другой процесс. По умолчанию значение равно 0.1.
min_parallel_table_scan_size
(integer
) #Устанавливает минимальное количество данных таблицы, которые должны быть просканированы, чтобы рассматривалось параллельное сканирование. Для параллельного последовательного сканирования количество просканированных данных таблицы всегда равно размеру таблицы, но при использовании индексов количество просканированных данных таблицы обычно будет меньше. Если это значение указано без единиц измерения, оно принимается в блоках, то есть
BLCKSZ
байт, обычно 8 кБ. По умолчанию установлено 8 мегабайт (8MB
).min_parallel_index_scan_size
(integer
) #Устанавливает минимальное количество данных индекса, которые должны быть просканированы, чтобы рассматривалось параллельное сканирование. Обратите внимание, что параллельное сканирование индекса обычно не затрагивает весь индекс; релевантно количество страниц, которые планировщик считает, что будут фактически затронуты сканированием. Этот параметр также используется для определения, может ли определенный индекс участвовать в параллельной очистке. См. VACUUM. Если это значение указано без единиц измерения, оно принимается в блоках, то есть в байтах
BLCKSZ
, обычно 8 кБ. По умолчанию установлено 512 килобайт (512 кБ
).effective_cache_size
(integer
) #Устанавливает предположение планировщика о фактическом размере дискового кеша, доступного для одного запроса. Это учитывается при оценке стоимости использования индекса; более высокое значение делает более вероятным использование сканирования индекса, более низкое значение делает более вероятным последовательное сканирование. При установке этого параметра следует учитывать как общие буферы Tantor SE-1C, так и часть дискового кеша ядра, которая будет использоваться для файлов данных Tantor SE-1C, хотя некоторые данные могут находиться и в одном, и в другом месте. Также учтите ожидаемое количество одновременных запросов к разным таблицам, так как им придется делить доступное пространство. Этот параметр не влияет на размер общей памяти, выделенной Tantor SE-1C, и не резервирует дисковый кеш ядра; он используется только для оценки. Система также не предполагает, что данные остаются в дисковом кеше между запросами. Если это значение указано без единиц измерения, оно принимается в блоках, то есть
BLCKSZ
байт, обычно 8 КБ. По умолчанию установлено 4 гигабайта (4GB
). (ЕслиBLCKSZ
не равно 8 КБ, значение по умолчанию масштабируется пропорционально).jit_above_cost
(floating point
) #Устанавливает стоимость запроса, выше которой активируется компиляция JIT, если она включена (см. Глава 30). Выполнение JIT требует времени на планирование, но может ускорить выполнение запроса. Установка значения
-1
отключает компиляцию JIT. По умолчанию установлено значение100000
.jit_inline_above_cost
(floating point
) #Устанавливает стоимость запроса, выше которой компилятор JIT пытается встраивать функции и операторы. Встраивание добавляет время планирования, но может улучшить скорость выполнения. Установка значения меньше чем
jit_above_cost
не имеет смысла. Установка значения-1
отключает встраивание. Значение по умолчанию -500000
.jit_optimize_above_cost
(floating point
) #Устанавливает стоимость запроса, выше которой применяются дорогостоящие оптимизации JIT-компиляции. Такая оптимизация добавляет время планирования, но может улучшить скорость выполнения. Не имеет смысла устанавливать это значение меньше, чем
jit_above_cost
, и маловероятно, что установка его больше, чемjit_inline_above_cost
, будет полезной. Установка этого значения равным-1
отключает дорогостоящие оптимизации. Значение по умолчанию -500000
.
18.7.3. Генетический оптимизатор запросов #
Генетический оптимизатор запросов (GEQO) - это алгоритм, который выполняет планирование запросов с использованием эвристического поиска. Это сокращает время планирования для сложных запросов (соединение множества отношений), но за счет того, что иногда создаются планы, которые хуже, чем те, которые находит обычный алгоритм полного перебора. Дополнительную информацию см. в Глава 59.
geqo
(boolean
) #Включает или отключает генетическую оптимизацию запросов. По умолчанию эта опция включена. Обычно лучше не отключать ее в продакшене; переменная
geqo_threshold
предоставляет более детальное управление GEQO.geqo_threshold
(integer
) #Используйте генетическую оптимизацию запросов для планирования запросов с не менее чем указанным количеством элементов
FROM
. (Обратите внимание, что конструкцияFULL OUTER JOIN
считается только одним элементомFROM
). По умолчанию это значение равно 12. Для более простых запросов обычно лучше использовать обычный планировщик с полным перебором, но для запросов с большим количеством таблиц полный перебор занимает слишком много времени, часто больше, чем штраф за выполнение неоптимального плана. Таким образом, установка порога на размер запроса является удобным способом управления использованием GEQO.geqo_effort
(integer
) #Управляет компромиссом между временем планирования и качеством плана запроса в GEQO. Эта переменная должна быть целым числом в диапазоне от 1 до 10. Значение по умолчанию - пять. Большие значения увеличивают время, затрачиваемое на планирование запроса, но также увеличивают вероятность выбора эффективного плана запроса.
geqo_effort
на самом деле ничего не делает непосредственно; он используется только для вычисления значений по умолчанию для других переменных, которые влияют на поведение GEQO (описанных ниже). Если хотите, вы можете установить другие параметры вручную.geqo_pool_size
(integer
) #Управляет размером пула, используемого GEQO, то есть количеством особей в генетической популяции. Он должен быть не менее двух, а полезные значения обычно составляют от 100 до 1000. Если он установлен в ноль (значение по умолчанию), то подходящее значение выбирается на основе
geqo_effort
и количества таблиц в запросе.geqo_generations
(integer
) #Управляет количеством поколений, используемых GEQO, то есть количество итераций алгоритма. Оно должно быть не менее одного, а полезные значения находятся в том же диапазоне, что и размер пула. Если установлено значение ноль (значение по умолчанию), то подходящее значение выбирается на основе
geqo_pool_size
.geqo_selection_bias
(floating point
) #Управляет смещением выбора, используемым GEQO. Смещение выбора - это селективное давление внутри популяции. Значения могут быть от 1.50 до 2.00; последнее является значением по умолчанию.
geqo_seed
(floating point
) #Управляет начальным значением генератора случайных чисел, используемого GEQO для выбора случайных путей в пространстве поиска порядка соединения. Значение может варьироваться от нуля (по умолчанию) до единицы. Изменение значения изменяет набор исследуемых путей соединения и может привести к нахождению лучшего или худшего пути.
18.7.4. Другие параметры планировщика #
default_statistics_target
(integer
) #Устанавливает целевое значение статистики по умолчанию для столбцов таблицы без установленного специфического значения цели через
ALTER TABLE SET STATISTICS
. Большие значения увеличивают время, необходимое для выполненияANALYZE
, но могут улучшить качество оценок планировщика. Значение по умолчанию - 100. Дополнительную информацию о использовании статистики планировщиком запросов Tantor SE-1C см. в разделе Раздел 14.2.constraint_exclusion
(enum
) #Управляет использованием планировщиком запросов ограничений таблиц для оптимизации запросов. Допустимые значения
constraint_exclusion
:on
(проверять ограничения для всех таблиц),off
(никогда не проверять ограничения) иpartition
(проверять ограничения только для дочерних таблиц наследования и подзапросовUNION ALL
). Значение по умолчанию -partition
. Оно часто используется с традиционными деревьями наследования для повышения производительности.Когда этот параметр позволяет это для конкретной таблицы, планировщик сравнивает условия запроса с
CHECK
ограничениями таблицы и пропускает сканирование таблиц, для которых условия противоречат ограничениям. Например:CREATE TABLE parent(key integer, ...); CREATE TABLE child1000(check (key between 1000 and 1999)) INHERITS(parent); CREATE TABLE child2000(check (key between 2000 and 2999)) INHERITS(parent); ... SELECT * FROM parent WHERE key = 2400;
С включенным исключением по ограничению, этот
SELECT
вообще не будет сканироватьchild1000
, что улучшает производительность.В настоящее время, исключение по ограничению включено по умолчанию только для случаев, которые часто используются для реализации секционирования таблицы через наследование. Включение его для всех таблиц накладывает дополнительные издержки на планирование, которые заметны при простых запросах, и в большинстве случаев не принесет пользы для простых запросов. Если у вас нет таблиц, которые разделены с использованием традиционного наследования, вы можете предпочесть полностью его отключить. (Обратите внимание, что эквивалентная функция для секционированных таблиц контролируется отдельным параметром, enable_partition_pruning).
Ссылка на Раздел 5.11.5 содержит дополнительную информацию о том, как использовать исключение по ограничению для реализации секционирования.
cursor_tuple_fraction
(floating point
) #Устанавливает оценку планировщика для доли строк курсора, которые будут извлечены. По умолчанию значение равно 0.1. Меньшие значения этого параметра склоняют планировщик к использованию планов “быстрого старта” для курсоров, которые быстро извлекают первые несколько строк, но могут затем долго извлекать все строки. Большие значения уделяют больше внимания общему предполагаемому времени. При максимальном значении 1.0 курсоры планируются точно так же, как и обычные запросы, учитывая только общее предполагаемое время, а не то, как скоро могут быть доставлены первые строки.
from_collapse_limit
(integer
) #Планировщик объединит подзапросы в верхние запросы, если результирующий список
FROM
не будет содержать более указанного количества элементов. Меньшие значения сокращают время планирования, но могут привести к менее эффективным планам запросов. По умолчанию значение равно восьми. Дополнительную информацию см. в разделе Раздел 14.3.Установка этого значения на geqo_threshold или выше может вызвать использование планировщика GEQO, что может привести к неоптимальным планам. См. Раздел 18.7.3.
jit
(boolean
) #Определяет, может ли JIT компиляция использоваться Tantor SE-1C, если доступно (см. Глава 30). По умолчанию
выключено
.join_collapse_limit
(integer
) #Планировщик будет переписывать явные конструкции
JOIN
(кромеFULL JOIN
) в списки элементовFROM
, когда результатом будет список из не более чем такого количества элементов. Меньшие значения сокращают время планирования, но могут привести к менее эффективным планам запроса.По умолчанию эта переменная устанавливается так же, как и
from_collapse_limit
, что подходит для большинства случаев. Установка ее значения равным 1 предотвращает любое переупорядочивание явныхJOIN
. Таким образом, явный порядок соединения, указанный в запросе, будет фактическим порядком соединения отношений. Поскольку планировщик запросов не всегда выбирает оптимальный порядок соединения, опытные пользователи могут временно установить эту переменную равной 1, а затем явно указать желаемый порядок соединения. Дополнительную информацию см. в разделе Раздел 14.3.Установка этого значения на geqo_threshold или выше может вызвать использование планировщика GEQO, что может привести к неоптимальным планам. См. Раздел 18.7.3.
plan_cache_mode
(enum
) #Все подготовленные операторы (явно подготовленные или неявно сгенерированные, например, PL/pgSQL) могут быть выполнены с использованием пользовательских или общих планов. Пользовательские планы создаются заново для каждого выполнения с использованием его конкретного набора значений параметров, в то время как общие планы не зависят от значений параметров и могут быть использованы повторно при последующих выполнениях. Таким образом, использование общего плана экономит время планирования, но если идеальный план сильно зависит от значений параметров, то общий план может быть неэффективным. Выбор между этими вариантами обычно делается автоматически, но его можно изменить с помощью параметра
plan_cache_mode
. Допустимые значения:auto
(по умолчанию),force_custom_plan
иforce_generic_plan
. Это настройка учитывается при выполнении кешированного плана, а не при его подготовке. Дополнительную информацию см. в разделе PREPARE.recursive_worktable_factor
(floating point
) #Устанавливает оценку планировщика среднего размера рабочей таблицы рекурсивного запроса в виде множителя от оцененного размера начального нерекурсивного срока запроса. Это помогает планировщику выбрать наиболее подходящий метод соединения рабочей таблицы с другими таблицами запроса. Значение по умолчанию -
10.0
. Меньшее значение, например,1.0
, может быть полезным, когда рекурсия имеет низкую степень расширения от одного шага к другому, например, в запросах кратчайшего пути. Запросы анализа графов могут получить выгоду от значений, превышающих значение по умолчанию.