F.22. HypoPG#

F.22. HypoPG

F.22. HypoPG

F.22.1. О HypoPG

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

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

Для получения более подробной информации, пожалуйста, обратитесь к официальной документации.

Версия: 1.4.0

GitHub

Авторское право (c) 2015-2023, Julien Rouhaud

F.22.2. Установка

Совместимо с Tantor SE 14+. Требуются файлы заголовков Tantor SE.

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

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

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

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

NOTE: Гипотетические индексы содержатся в одном бэкенде. Следовательно, если вы добавляете несколько гипотетических индексов, параллельные соединения, выполняющие 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 |                 indexname                 | nspname | relname | amname
 -----------+-------------------------------------------+---------+---------+--------
     205101 | <41072>btree_hypo_id                      | public  | hypo    | btree

Если вам нужна более техническая информация о гипотетических индексах, функция 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 в текущей сессии и не будет влиять на другие сессии.