F.2. aqo

Модуль aqo представляет собой расширение Postgres Pro Enterprise для оптимизации запросов по стоимости выполнения. Используя методы машинного обучения, а точнее модификацию алгоритма k-NN, aqo улучшает оценку количества строк, что может способствовать выбору лучшего плана и, как следствие, ускорению запросов.

Модуль aqo может собирать статистику по всем выполняемым запросам, за исключением запросов, обращающихся к системным отношениям. Если запросы различаются только константами, они считаются относящимися к одному классу. Для каждого класса модуль aqo сохраняет для машинного обучения качество оценки количества строк, время планирования, время и статистику выполнения. Но основе этих данных aqo строит новый план выполнения и использует его для следующего запроса того же класса. В тестах aqo показал значительное увеличение производительности для сложных запросов.

F.2.1. Установка и подготовка

Расширение aqo включено в состав Postgres Pro Enterprise. Установив Postgres Pro Enterprise, выполните следующие действия, чтобы подготовить aqo к работе:

  1. Добавьте aqo в параметр shared_preload_libraries в файле postgresql.conf:

    shared_preload_libraries = 'aqo'

    Библиотеку aqo нужно предварительно загрузить при запуске сервера, так как адаптивная оптимизация запросов должна быть включена для всего кластера. В противном случае aqo будет работать только в тех сеансах, в которых вы создадите расширение aqo.

  2. Создайте расширение aqo, выполнив следующий запрос:

    CREATE EXTENSION aqo;

Когда расширение будет создано, вы можете приступить к оптимизации запросов.

Чтобы отключить aqo на уровне кластера и удалить всю собранную статистику, выполните:

DROP EXTENSION aqo;

F.2.1.1. Конфигурирование

По умолчанию aqo не влияет на быстродействие запросов. Чтобы включить адаптивную оптимизацию запросов для базы данных, добавьте переменную aqo.mode в файл postgresql.conf и перезапустите кластер. В зависимости от модели использования базы данных вы можете выбрать один из следующих режимов:

  • intelligent — в этом режиме выполняется автонастройка запросов на основе статистики, собранной по классам запросов.

  • forced — в этом режиме предпринимается попытка оптимизировать все новые запросы на общих основаниях, вне зависимости от их класса.

  • controlled — в этом режиме используется стандартный планировщик для любых новых запросов, но для уже известных классов запросов продолжают использоваться ранее заданные параметры планирования.

  • learn — в этом режиме собирается статистика по всем выполненным запросам и обновляются данные о классах запросов.

  • disabled — в этом режиме aqo отключается для всех запросов, даже для запросов известных классов. Этот режим можно использовать для временного отключения aqo с сохранением конфигурации и собранной статистики.

Чтобы динамически изменить параметры aqo в текущем сеансе, выполните следующую команду:

SET aqo.mode = 'режим';

Здесь режим — название режима работы, который будет использоваться.

Важно

В режиме intelligent aqo может работать не очень хорошо, если в вашей рабочей нагрузке встречаются запросы множества разных классов. В этом случае вы можете попробовать сменить режим на controlled.

F.2.2. Использование

F.2.2.1. Выбор режима работы для оптимизации запросов

Если у вас часто выполняются однотипные запросы, например, ваше приложение выдаёт ограниченное число всевозможных классов запросов, вы можете воспользоваться интеллектуальным режимом (intelligent) для улучшения планирования таких запросов. В этом режиме aqo анализирует выполнение каждого запроса и собирает статистику. При этом статистика по разным классам запросов собирается отдельно. Если производительность не увеличивается после 50 итераций, расширение aqo уступает планирование стандартному планировщику запросов.

Примечание

Вы можете просмотреть текущий план запроса, воспользовавшись стандартной командой Postgres Pro EXPLAIN с указанием ANALYZE. За подробностями обратитесь к Разделу 14.1.

Так как в режиме intelligent различные классы запросов анализируются отдельно, aqo может не улучшить производительность, если запросы в рабочей нагрузке постоянно меняются. Для такого динамического профиля нагрузки стоит перевести aqo в режим controlled или попробовать режим forced.

В режиме forced aqo не разделяет собранную статистику по классам запросов и пытается оптимизировать их одинаково. Этот режим может быть полезен для оптимизации нагрузки с множеством различных классов запросов и требует меньше памяти, чем интеллектуальный режим. Но так как в режиме forced не производится интеллектуальная настройка на класс запроса, для некоторых запросов производительность может снизиться. Если вы наблюдаете снижение производительности в этом режиме, переключите aqo в режим controlled.

В контролируемом режиме (controlled) aqo не собирает статистику для новых классов запросов, так что они не будут оптимизироваться. Для ранее наблюдавшихся классов запросов aqo будет продолжать собирать статистику и применять оптимизированные алгоритмы планирования.

В режиме learn собирается статистика по всем выполненным запросам и обновляются данные о классах запросов. Этот режим похож на режим intelligent, за исключением того, что интеллектуальная настройка на класс запроса не производится.

Если вы хотите полностью отключить aqo, вы можете переключить его в режим disabled. В этом случае для всех запросов будет использоваться стандартный планировщик, но конфигурация и собранная статистика aqo сохранятся для возможного использования в будущем.

F.2.2.2. Тонкая настройка aqo

Для обращения к таблицам aqo и изменения расширенных свойств запросов необходимо иметь права суперпользователя.

Работая в интеллектуальном режиме (intelligent), aqo назначает уникальное хеш-значение каждому классу запросов для разделения собираемой статистики. В режиме forced статистика всех ранее ненаблюдаемых классов запросов собирается вместе, в одной записи для общего класса с хешем, равным 0. Просмотреть все обработанные классы запросов и их хеш-значения можно в таблице aqo_query_texts:

SELECT * FROM aqo_query_texts;

Разные классы запросов имеют собственные свойства оптимизации. Эти свойства хранятся в таблице aqo_queries:

SELECT * FROM aqo_queries;

Для каждого класса запросов хранятся следующие свойства:

  • query_hash содержит хеш-значение, однозначно идентифицирующее класс запроса.

  • learn_aqo включает сбор статистики для данного класса запросов.

  • use_aqo включает предсказание количества строк средствами aqo для следующего выполнения данного класса запросов.

  • fspace_hash содержит уникальный идентификатор отдельного пространства, в котором собирается статистика для этого класса запросов. По умолчанию fspace_hash равняется query_hash.

  • auto_tuning показывает, будет ли aqo пытаться менять другие параметры для данного запроса. По умолчанию автонастройка включена в интеллектуальном режиме (intelligent).

Вы можете вручную изменять эти свойства, чтобы скорректировать оптимизацию для определённого класса запросов. Например:

 -- Добавление нового класса запросов в таблицу aqo_queries:

SET aqo.mode='intelligent';
SELECT * FROM a, b WHERE a.id=b.id;
SET aqo.mode='controlled';

 -- Отключение автонастройки, включение learn_aqo и use_aqo 
 -- для данного класса запросов:

UPDATE aqo_queries SET use_aqo=true, learn_aqo=true, auto_tuning=false 
  WHERE query_hash = (SELECT query_hash from aqo_query_texts 
  WHERE query_text LIKE 'SELECT * FROM a, b WHERE a.id=b.id;');

 -- Запуск EXPLAIN ANALYZE и наблюдение изменённого плана:

EXPLAIN ANALYZE SELECT * FROM a, b WHERE a.id=b.id;
EXPLAIN ANALYZE SELECT * FROM a, b WHERE a.id=b.id;

 -- Отключение обучения для прекращения сбора статистики и
 -- начала использования оптимизированного плана:

UPDATE aqo_queries SET learn_aqo=false 
  WHERE query_hash = (SELECT query_hash from aqo_query_texts 
  WHERE query_text LIKE 'SELECT * FROM a, b WHERE a.id=b.id;');

Если распределение данных или запросы быстро меняются, накопление полезной статистики может занять больше чем обычно. В этом случае использование неактуальной статистики может отражаться на производительности. Для ускорения обучения aqo статистику можно сбросить. Чтобы удалить всю накопленную статистику машинного обучения, выполните следующую команду:

DELETE FROM aqo_data;

Также можно сбросить статистику для определённого класса запросов, добавив ограничение поля fspace_hash по его хешу. Например:

DELETE FROM aqo_data WHERE fspace_hash = (SELECT fspace_hash FROM aqo_queries 
  WHERE query_hash = (SELECT query_hash from aqo_query_texts 
  WHERE query_text LIKE 'SELECT * FROM a, b WHERE a.id=b.id;'));

Чтобы предотвратить интеллектуальную настройку для определённого класса запросов, отключите свойство auto_tuning:

UPDATE aqo_queries SET auto_tuning=false WHERE query_hash = 'хеш';

Здесь хеш — это значение хеша для данного класса запросов. В результате aqo не будет автоматически менять свойства learn_aqo и use_aqo.

Чтобы отключить дальнейшее обучение для некоторого класса запросов, выполните следующую команду:

UPDATE aqo_queries SET learn_aqo=false WHERE query_hash = 'хеш';

Здесь хеш — это значение хеша для данного класса запросов.

Чтобы полностью отключить aqo для всех запросов и использовать стандартный планировщик PostgreSQL, выполните:

UPDATE aqo_queries SET use_aqo=false, learn_aqo=false, auto_tuning=false;

F.2.3. Справка

F.2.3.1. Конфигурационные переменные

F.2.3.1.1. aqo.mode

Определяет режим оптимизации aqo.

Таблица F.3. Параметры aqo.mode

ЗначениеОписание
intelligentАвтонастройка запросов на основе статистики, собранной по классам запросов.
forcedСобирается статистика по всем запросам, вне зависимости от их класса.
controlledРежим по умолчанию. Для всех новых запросов используется стандартный планировщик, но для уже известных классов запросов может использоваться ранее собранная статистика.
learnСобирается статистика по всем выполненным запросам и обновляются данные о классах запросов.
disabledПолностью отключает aqo для всех запросов. При этом конфигурация и собранная статистика aqo сохраняется для возможного использования в будущем.

F.2.3.2. Таблицы

Важно

Вы можете вручную изменить параметры оптимизации в таблице aqo_queries. Модифицировать содержимое других таблиц следует только при чётком понимании механизмов адаптивной оптимизации.

F.2.3.2.1. Таблица aqo_query_texts

В таблице aqo_query_texts классифицируются все классы запросов, обрабатываемые aqo.

Таблица F.4. Таблица aqo_query_texts

Имя столбцаОписание
query_hashСодержит хеш-значение, однозначно идентифицирующее класс запроса.
query_textСодержит текст первого проанализированного запроса данного класса.

F.2.3.2.2. Таблица aqo_queries

Таблица aqo_queries содержит свойства оптимизации для разных классов запросов.

Таблица F.5. Таблица aqo_queries

СвойствоОписание
query_hashСодержит хеш-значение, однозначно идентифицирующее класс запроса.
learn_aqoВключает сбор статистики для данного класса запросов.
use_aqoВключает предсказание количества строк средствами aqo для следующего выполнения данного класса запросов. Если модель оценки стоимости неполная, это может привести к замедлению при выполнении запросов.
fspace_hashЗадаёт уникальный идентификатор отдельного пространства, в котором собирается статистика для данного класса запросов. По умолчанию fspace_hash равняется query_hash. Вы можете присвоить ему другой query_hash, чтобы оптимизировать разные классы запросов вместе. В результате может сократиться объём памяти для моделей и даже увеличиться скорость запросов. Однако изменение этого свойства может приводить и к неожиданному поведению aqo, так что использовать это следует, только если вы точно понимаете, что делаете.
auto_tuningОпределяет, будет ли aqo пытаться настраивать другие свойства выполнения для данного запроса. По умолчанию автонастройка включена в интеллектуальном режиме. В других режимах новые запросы не добавляются в aqo_queries автоматически. Вы можете изменить это поведение, присвоив переменной auto_tuning значение true.

F.2.3.2.3. Таблица aqo_data

Таблица aqo_data содержит данные машинного обучения для уточнения оценки количества строк. Чтобы стереть всю собранную статистику для определённого класса запросов, вы можете удалить из таблицы aqo_data все строки с соответствующим fspace_hash.

F.2.3.2.4. Таблица aqo_query_stat

Таблица aqo_query_stat содержит статистику выполнения запросов, группируемую по классам запросов. Расширение aqo использует эти данные, когда для определённого класса запросов включено свойство auto_tuning.

Таблица F.6. Таблица aqo_query_stat

ДанныеОписание
execution_time_with_aqoВремя выполнения запросов со включённым aqo.
execution_time_without_aqoВремя выполнения запросов с отключённым aqo.
planning_time_with_aqoВремя планирования запросов со включённым aqo.
planning_time_without_aqoВремя планирования запросов с отключённым aqo.
cardinality_error_with_aqoОшибка оценки количества строк в планах запросов, выбранных со включённым aqo.
cardinality_error_without_aqoОшибка оценки количества строк в планах запросов, выбранных с отключённым aqo.
executions_with_aqoЧисло запросов, выполненных со включённым aqo.
executions_without_aqoЧисло запросов, выполненных с отключённым aqo.

F.2.4. Автор

Олег Иванов

F.2. aqo

The aqo module is a Postgres Pro Enterprise extension for cost-based query optimization. Using machine learning methods, more precisely, a modification of the k-NN algorithm, aqo improves cardinality estimation, which can optimize execution plans and, consequently, speed up query execution.

The aqo module can collect statistics on all the executed queries, excluding the queries that access system relations. The collected statistics is classified by query class. If the queries differ in their constants only, they belong to the same class. For each class, aqo stores the cardinality quality, planning time, execution time, and execution statistics for machine learning. Based on this data, aqo builds a new query plan and uses it for the next query of the same class. aqo test runs have shown significant performance improvements for complex queries.

F.2.1. Installation and Setup

The aqo extension is included into Postgres Pro Enterprise. Once you have Postgres Pro Enterprise installed, complete the following steps to enable aqo:

  1. Add aqo to the shared_preload_libraries parameter in the postgresql.conf file:

    shared_preload_libraries = 'aqo'
    

    The aqo library must be preloaded at the server startup, since adaptive query optimization needs to be enabled per cluster. Otherwise, aqo will only be used for the session in which you created the aqo extension.

  2. Create the aqo extension using the following query:

    CREATE EXTENSION aqo;
    

Once the extension is created, you can start optimizing queries.

To disable aqo at the cluster level and remove all the collected statistics, run:

DROP EXTENSION aqo;

F.2.1.1. Configuration

By default, aqo does not affect query performance. To enable adaptive query optimization for your database, add the aqo.mode variable to your postgresql.conf file and reload the cluster. Depending on your database usage model, you can choose between the following modes:

  • intelligent — this mode auto-tunes your queries based on statistics collected per query class.

  • forced — this mode tries to optimize all new queries together, regardless of the query class.

  • controlled — this mode uses the default planner for all new queries, but continues using the previously specified planning settings for already known query classes, if any.

  • learn — this mode collects statistics on all the executed queries and updates the data for query classes.

  • disabled — this mode disables aqo for all queries, even for the known query classes. You can use this mode to temporarily disable aqo without losing the collected statistics and configuration.

To dynamically change the aqo settings in your current session, run the following command:

SET aqo.mode = 'mode';

where mode is the name of the operation mode to use.

Important

The intelligent mode of aqo may not work well if the queries in your workload are of multiple different classes. In this case, you can try resetting the mode to controlled.

F.2.2. Usage

F.2.2.1. Choosing Operation Mode for Query Optimization

If you often run queries of the same class, for example, your application limits the number of possible query classes, you can use the intelligent mode to improve planning for these queries. In this mode, aqo analyzes each query execution and stores statistics. Statistics on queries of different classes is stored separately. If performance is not improved after 50 iterations, the aqo extension falls back to the default query planner.

Note

You can view the current query plan using the standard Postgres Pro EXPLAIN command with the ANALYZE option. For details, see the Section 14.1.

Since the intelligent mode tries to learn separately for different query classes, aqo may fail to provide performance improvements if the classes of the queries in the workload are constantly changing. For such dynamic workloads, reset the aqo extension to the controlled mode, or try using the forced mode.

In the forced mode, aqo does not classify the collected statistics by query classes and tries to optimize all queries together. This mode can help you optimize workloads with multiple different query classes, and it consumes less memory than the intelligent mode. However, since the forced mode lacks intelligent tuning, performance may decrease for some queries. If you see performance issues in this mode, switch aqo to the controlled mode.

In the controlled mode, aqo does not collect statistics for new query classes, so they will not be optimized. For known query classes, aqo will continue collecting statistics and using optimized planning algorithms.

The learn mode collects statistics from all the executed queries and updates the data for query classes. This mode is similar to the intelligent mode, except that it doesn't provide intelligent tuning.

If you want to fully disable aqo, you can switch aqo to the disabled mode. In this case, the default planner is used for all queries, but the collected statistics and aqo settings are saved and can be used in the future.

F.2.2.2. Fine-Tuning aqo

You must have superuser rights to access aqo tables and configure advanced query settings.

When run in the intelligent mode, aqo assigns a unique hash value to each query class to separate the collected statistics. If you switch to the forced mode, the statistics for all untracked query classes is stored in a common query class with hash 0. You can view all the processed query classes and their corresponding hash values in the aqo_query_texts table:

SELECT * FROM aqo_query_texts;

Each query class has its own optimization settings. These settings are stored in the aqo_queries table:

SELECT * FROM aqo_queries;

For each query class, the following settings are available:

  • query_hash stores the hash value that uniquely identifies the query class.

  • learn_aqo enables statistics collection for this query class.

  • use_aqo enables aqo cardinality prediction for the next execution of this query class.

  • fspace_hash is a unique identifier of the separate space in which the statistics for this query class is collected. By default, fspace_hash is equal to query_hash.

  • auto_tuning shows whether aqo tries to change other settings for the given query. By default, auto-tuning is enabled in the intelligent mode.

You can manually change these settings to adjust optimization for a particular query class. For example:

 -- Add a new query class into the aqo_queries table:

SET aqo.mode='intelligent';
SELECT * FROM a, b WHERE a.id=b.id;
SET aqo.mode='controlled';

 -- Disable auto_tuning, enable both learn_aqo and use_aqo 
 -- for this query class:

UPDATE aqo_queries SET use_aqo=true, learn_aqo=true, auto_tuning=false 
  WHERE query_hash = (SELECT query_hash from aqo_query_texts 
  WHERE query_text LIKE 'SELECT * FROM a, b WHERE a.id=b.id;');

 -- Run EXPLAIN ANALYZE until the plan changes:

EXPLAIN ANALYZE SELECT * FROM a, b WHERE a.id=b.id;
EXPLAIN ANALYZE SELECT * FROM a, b WHERE a.id=b.id;

 -- Disable learning to stop statistics collection 
 -- and use the optimized plan:

UPDATE aqo_queries SET learn_aqo=false 
  WHERE query_hash = (SELECT query_hash from aqo_query_texts 
  WHERE query_text LIKE 'SELECT * FROM a, b WHERE a.id=b.id;');

If your data or query distribution is rapidly changing, learning new statistics will take longer than usual. In this case, obsolete statistics may affect performance. To speed up aqo learning, reset the statistics. To remove all the collected machine learning statistics, run the following command:

DELETE FROM aqo_data;

Alternatively, you can specify a particular query class to reset by providing its hash value in the fspace_hash option. For example:

DELETE FROM aqo_data WHERE fspace_hash = (SELECT fspace_hash FROM aqo_queries 
  WHERE query_hash = (SELECT query_hash from aqo_query_texts 
  WHERE query_text LIKE 'SELECT * FROM a, b WHERE a.id=b.id;'));

To stop intelligent tuning for a particular query class, disable the auto_tuning setting:

UPDATE aqo_queries SET auto_tuning=false WHERE query_hash = 'hash';

where hash is the hash value for this query class. As a result, aqo disables automatic changing of the learn_aqo and use_aqo settings.

To disable further learning for a particular query class, use the following command:

UPDATE aqo_queries SET learn_aqo=false WHERE query_hash = 'hash';

where hash is the hash value for this query class.

To fully disable aqo for all queries and use the default PostgreSQL query planner, run:

UPDATE aqo_queries SET use_aqo=false, learn_aqo=false, auto_tuning=false;

F.2.3. Reference

F.2.3.1. Configuration Variables

F.2.3.1.1. aqo.mode

Defines aqo optimization modes.

Table F.3. aqo.mode Options

OptionDescription
intelligentAuto-tunes your queries based on statistics collected per query class.
forcedCollects statistics for all queries altogether without any classification.
controlledDefault. Uses the default planner for all new queries, but can reuse the collected statistics for already known query classes, if any.
learnCollects statistics on all the executed queries and updates the data for query classes.
disabledFully disables aqo for all queries. The collected statistics and aqo settings are saved and can be used in the future.

F.2.3.2. Tables

Important

You can manually change optimization settings in the aqo_queries table. You may also modify other tables, but only if you understand the logic of adaptive query optimization.

F.2.3.2.1. aqo_query_texts Table

The aqo_query_texts table classifies all the query classes processed by aqo. For each query class, the table contains the text of the first analyzed query of this class.

Table F.4. aqo_query_texts Table

Column NameDescription
query_hashStores the hash value that uniquely identifies the query class.
query_textProvides the text of the first analyzed query of the given class.

F.2.3.2.2. aqo_queries Table

The aqo_queries table stores optimization settings for different query classes.

Table F.5. aqo_queries Table

SettingDescription
query_hashStores the hash value that uniquely identifies the query class.
learn_aqoEnables statistics collection for this query class.
use_aqoEnables aqo cardinality prediction for the next execution of this query class. If cost estimation model is incomplete, this may slow down query execution.
fspace_hashProvides a unique identifier of the separate space in which the statistics for this query class is collected. By default, fspace_hash is equal to query_hash. You can change this setting to a different query_hash to optimize different query classes together. It may decrease the amount of memory for models and even improve query execution performance. However, changing this setting may cause unexpected aqo behavior, so make sure to use it only if you know what you are doing.
auto_tuningShows whether aqo tries to tune other settings for the given query. By default, auto-tuning is enabled in the intelligent mode. In other modes, new queries are not appended to aqo_queries automatically. You can change this behavior by setting the auto_tuning variable to true.

F.2.3.2.3. aqo_data Table

The aqo_data table contains machine learning data for cardinality estimation refinement. To forget all the collected statistics for a particular query class, you can delete all rows from aqo_data with the corresponding fspace_hash.

F.2.3.2.4. aqo_query_stat Table

The aqo_query_stat table stores statistics on query execution, by query class. The aqo extension uses this data when the auto_tuning option is enabled for a particular query class.

Table F.6. aqo_query_stat Table

DataDescription
execution_time_with_aqoExecution time for queries run with aqo enabled.
execution_time_without_aqoExecution time for queries run with aqo disabled.
planning_time_with_aqoPlanning time for queries run with aqo enabled.
planning_time_without_aqoPlanning time for queries run with aqo disabled.
cardinality_error_with_aqoCardinality estimation error in the selected query plans with aqo enabled.
cardinality_error_without_aqoCardinality estimation error in the selected query plans with aqo disabled.
executions_with_aqoNumber of queries run with aqo enabled.
executions_without_aqoNumber of queries run with aqo disabled.

F.2.4. Author

Oleg Ivanov

FAQ