F.24. HypoPG — поддержка гипотетических индексов#

F.24. HypoPG — поддержка гипотетических индексов

F.24. HypoPG — поддержка гипотетических индексов #

Версия: 1.4.2

F.24.1. Обзор #

HypoPG - это расширение Tantor SE-1C, добавляющее поддержку гипотетических индексов.

Гипотетический или виртуальный индекс - это индекс, который на самом деле не существует. То есть, для его создания не требуется никаких ресурсов процессора, диска или прочих ресурсов. Полезно знать, могут ли определенные индексы улучшить производительность для проблемных запросов, так как тогда вы будете узнать, будет ли Tantor SE-1C использовать эти индексы или нет, не тратя ресурсы на их создание.

F.24.2. Установка #

Tantor SE-1C требуются заголовочные файлы.

  • В каждой базе данных: CREATE EXTENSION hypopg;

F.24.3. Обновление расширения #

Обратите внимание, что hypopg не предоставляет скриптов обновления расширений, поскольку данные не сохраняются ни в одном из созданных объектов. Поэтому вам нужно сначала удалить расширение, а затем создать его снова, чтобы получить новую версию.

F.24.4. Обновление расширения #

Обратите внимание, что hypopg не предоставляет скрипты обновления расширения, так как никакие данные не сохраняются ни в одном из созданных объектов. Поэтому для получения новой версии вам нужно сначала удалить расширение, а затем создать его снова.

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

Примечание

Гипотетические индексы содержатся в одном серверном процессе. Поэтому, если вы добавите несколько гипотетических индексов, параллельные подключения, выполняющие EXPLAIN, не будут затронуты вашими гипотетическими индексами.

Возьмем простой тестовый случай:

rjuju=# CREATE TABLE hypo AS SELECT id, 'line ' || id AS val FROM generate_series(1,10000) id;
rjuju=# EXPLAIN SELECT * FROM hypo WHERE id = 1;
                      QUERY PLAN
-------------------------------------------------------
 Seq Scan on hypo  (cost=0.00..180.00 rows=1 width=13)
   Filter: (id = 1)
(2 rows)

Самый простой способ создать гипотетический индекс - использовать функции hypopg_create_index с обычным оператором CREATE INDEX в качестве аргумента.

Например:

rjuju=# SELECT * FROM hypopg_create_index('CREATE INDEX ON hypo (id)');

Некоторая информация из команды CREATE INDEX будет проигнорирована, например, имя индекса, если оно указано. Некоторая из игнорируемой информации будет обработана в будущем выпуске.

Вы можете проверить доступные гипотетические индексы в своей собственной системе:

rjuju=# SELECT * FROM hypopg_list_indexes ;
 indexrelid |          index_name           | schema_name | table_name | am_name 
------------+-------------------------------+-------------+------------+---------
      50573 | <50573>btree_hypo_id          | public      | hypo       | btree

Если команда CREATE INDEX, которую вы хотите использовать, также требует экранирования, рекомендуется использовать синтаксис долларового экранирования. Например:

rjuju=# SELECT * FROM hypopg_create_index($$CREATE INDEX ON hypo (id) WHERE val = 'line 1'$$);

Если вам нужна более техническая информация о гипотетических индексах, функция hypopg() вернет гипотетические индексы также, как это делает системный каталог pg_index.

И теперь, давайте посмотрим, будет ли ваше предыдущий оператор EXPLAIN использовать такой индекс:

rjuju=# EXPLAIN SELECT * FROM hypo WHERE id = 1;
                                     QUERY PLAN
------------------------------------------------------------------------------------
 Index Scan using <41072>hypo_btree_hypo_id on hypo  (cost=0.29..8.30 rows=1 width=13)
   Index Cond: (id = 1)
(2 rows)

Разумеется, только EXPLAIN без ANALYZE будет использовать гипотетические индексы:

rjuju=# EXPLAIN ANALYZE SELECT * FROM hypo WHERE id = 1;
                                           QUERY PLAN
-------------------------------------------------------------------------------------------------
 Seq Scan on hypo  (cost=0.00..180.00 rows=1 width=13) (actual time=0.036..6.072 rows=1 loops=1)
   Filter: (id = 1)
   Rows Removed by Filter: 9999
 Planning time: 0.109 ms
 Execution time: 6.113 ms
(5 rows)

Чтобы удалить гипотетические индексы вашего бэкенда, вы можете использовать функцию hypopg_drop_index(indexrelid) с OID, которая возвращает представление hypopg_list_indexes, и вызвать hypopg_reset() для удаления всех индексов сразу, или просто закрыть ваше текущее соединение.

Продолжая разбор приведенного выше примера, вы можете скрыть существующие индексы, но сначала следует использовать hypopg_reset() для сброса предыдущих эффектов других индексов.

Создайте два реальных индекса и запустите EXPLAIN:

rjuju=# SELECT hypopg_reset();
rjuju=# CREATE INDEX ON hypo(id);
rjuju=# CREATE INDEX ON hypo(id, val);
rjuju=# EXPLAIN SELECT * FROM hypo WHERE id = 1;
                                    QUERY PLAN
----------------------------------------------------------------------------------
Index Only Scan using hypo_id_val_idx on hypo  (cost=0.29..8.30 rows=1 width=13)
Index Cond: (id = 1)
(2 rows)

План запроса использует индекс hypo_id_val_idx. Используйте hypopg_hide_index(oid) для скрытия одного из индексов:

rjuju=# SELECT hypopg_hide_index('hypo_id_val_idx'::REGCLASS);
rjuju=# EXPLAIN SELECT * FROM hypo WHERE id = 1;
                            QUERY PLAN
-------------------------------------------------------------------------
Index Scan using hypo_id_idx on hypo  (cost=0.29..8.30 rows=1 width=13)
Index Cond: (id = 1)
(2 rows)

План запроса теперь использует другой индекс hypo_id_idx. Используйте hypopg_hide_index(oid) чтобы скрыть его:

rjuju=# SELECT hypopg_hide_index('hypo_id_idx'::REGCLASS);
rjuju=# EXPLAIN SELECT * FROM hypo WHERE id = 1;
                    QUERY PLAN
-------------------------------------------------------
Seq Scan on hypo  (cost=0.00..180.00 rows=1 width=13)
Filter: (id = 1)
(2 rows)

И теперь план запроса возвращается к Seq Scan. Используйте hypopg_unhide_index(oid) для восстановления индекса:

rjuju=# SELECT hypopg_unhide_index('hypo_id_idx'::regclass);
rjuju=# EXPLAIN SELECT * FROM hypo WHERE id = 1;
                            QUERY PLAN
-------------------------------------------------------------------------
Index Scan using hypo_id_idx on hypo  (cost=0.29..8.30 rows=1 width=13)
Index Cond: (id = 1)
(2 rows)

Конечно, вы также можете скрывать гипотетические индексы:

rjuju=# SELECT hypopg_create_index('CREATE INDEX ON hypo(id)');
rjuju=# EXPLAIN SELECT * FROM hypo WHERE id = 1;
                                    QUERY PLAN
------------------------------------------------------------------------------------
Index Scan using "<12659>btree_hypo_id" on hypo  (cost=0.04..8.05 rows=1 width=13)
Index Cond: (id = 1)
(2 rows)

rjuju=# SELECT hypopg_hide_index(12659);
rjuju=# EXPLAIN SELECT * FROM hypo WHERE id = 1;
                    QUERY PLAN
-------------------------------------------------------
Seq Scan on hypo  (cost=0.00..180.00 rows=1 width=13)
Filter: (id = 1)
(2 rows)

Вы можете проверить, какие индексы скрыты, используя hypopg_hidden_indexes() или представление hypopg_hidden_indexes:

rjuju=# SELECT * FROM hypopg_hidden_indexes();
indexid
---------
526604
526603
12659
(3 rows)

rjuju=# SELECT * FROM hypopg_hidden_indexes;
  indexrelid |      index_name      | schema_name | table_name | am_name | is_hypo
------------+----------------------+-------------+------------+---------+---------
      12659  | <12659>btree_hypo_id | public      | hypo       | btree   | t
      526603 | hypo_id_idx          | public      | hypo       | btree   | f
      526604 | hypo_id_val_idx      | public      | hypo       | btree   | f
(3 rows)

Чтобы восстановить все существующие индексы, вы можете использовать функцию hypopg_unhide_all_indexes(). Обратите внимание, что скрытие существующих индексов применимо только к команде EXPLAIN в текущей сессии и не будет влиять на другие сессии.