153 lines
10 KiB
Markdown
153 lines
10 KiB
Markdown
---
|
||
aliases:
|
||
- индексирования
|
||
tags:
|
||
- зрелость/🌱
|
||
date:
|
||
- - 2024-03-31
|
||
zero-link:
|
||
- "[[00 PostgreSQL]]"
|
||
parents:
|
||
linked:
|
||
---
|
||
Индекс это служебная структура данных, которая позволяет ускорить запросы (поиск, сортировку) к базе данных.
|
||
|
||
**Польза:**
|
||
- Ускоряют запросы: равенство, сравнения, сортировка
|
||
- В некоторых случаях позволяют избежать чтения из таблицы. [Покрывающий индекс](Покрывающий%20индекс.md).
|
||
- Через них можно делать constraints (UNIQUE, FOREIGN KEY)
|
||
- Специальные оптимизации?
|
||
|
||
**Накладные расходы:**
|
||
- Дополнительные объемы дискового пространства для хранения индекса. Размер индекса в половину размера таблицы считается нормальным и оптимальным
|
||
- Обновляются при модификации данных, на что требуется время и ресурсы. Замедление записи в таблицы (80% к 20%). Так как необходимо будет перестраивать индекс при вставке новых значений.
|
||
- Усложненное технического обслуживание. Индексы пухнут и переодически их нужно пересоздавать
|
||
|
||
**Когда индексы не нужны?**
|
||
- Малая [Селективность колонки](Селективность%20колонки.md).
|
||
- Большие накладные расходы на поддержание индекса.
|
||
- Когда индекс не используется вовсе.
|
||
|
||
**Когда индексы не работают?**
|
||
- В условии используется вычисляемое выражение: `WHERE counter + 1 = 46`
|
||
- Если будет отобрано слишком много записей.
|
||
- Из агрегирующих функций только `min()` и `max()` получат ускорение.
|
||
- Индексы хорошо работают с логическим И, и плохо работают с логическим ИЛИ.
|
||
- `SELECT * FROM tb WHERE a = 0 OR b = 0;`
|
||
- Можно использовать 2 индекса (а) и (b). Индекс (а, b) работать не будет.
|
||
|
||
**Какие бывают индексы?**
|
||
- Не уникальные и уникальные. Уникальные без повторяющихся значений.
|
||
- Простые и [составные](Составные%20индексы%20в%20PostgreSQL.md).
|
||
- Кластерные и некластерные. Кластерные также хранят сами данные рядом с собой.
|
||
|
||
**Типы индексов**
|
||
- btree
|
||
- Основан на работе [B-tree](B-tree.md) дерева
|
||
- Наиболее распространенный тип индексов
|
||
- Очень хороший алгоритм работы
|
||
- Покрывает 90% задач
|
||
- Легко создать ориентируясь на статистику по таблице
|
||
- Обслуживает как операции сравнения так и операции равенства
|
||
- Позволяет выполнить сортировку
|
||
- hash индекс
|
||
- Абсолютно бесполезен. Используйте btree.
|
||
- Занимает меньше места на диске, чем btree.
|
||
- Обслуживает только операции равенства.
|
||
- Нельзя выполнить сортировку.
|
||
- gist индекс
|
||
- В чистом виде полезен для гео-данных. Например, поиск ближайшей гео-точки.
|
||
- Расширения
|
||
- pg_trgm - like, ilike, ~, ~* (regexp)
|
||
- btree_gits - слодные constrains с интервалами. Позволяет переложить на базу данных задачу по контролю пересечения времени. Например, если нужно создать расписание, и чтобы временные интервалы заданий не пересекались.
|
||
- sp_gist индекс
|
||
- Нет практических применений в [OLTP](OLTP.md)
|
||
- Возможно полезен в научной сфере
|
||
- gin индекс. Нужен тип данных tsvector
|
||
- Может сильно ухудшить время вставки в таблицу
|
||
- Хорошо для текстового поиска
|
||
- Позволяет ускорить поиск по jsonb
|
||
- jsonb_ops - используется по умолчанию. Индексирует все значения jsonb, из-за этого индекс получается больших размеров.
|
||
- json_path_ops - заточен на поиск путей в json. То есть позволяет ответить, есть ли такое-то поле в jsonb или его нет.
|
||
- brin
|
||
- Компактный индекс
|
||
- Подходит для упорядоченных данных
|
||
|
||
## Создание индекса
|
||
**Что нужно для создания индекса?**
|
||
- Ориентироваться только на продуктовое окружение, так как тестовые окружения не соответствуют реальности.
|
||
- Собрать статистику нагрузки на БД от запросов.
|
||
- Представление [pg_stats](Таблица%20статистик%20pg_stats.md).
|
||
- Инструменты для сбора статистики:
|
||
- [pg_stat_statements](pg_stat_statements.md) - отличный инструмент
|
||
- pgBadger - использовать с осторожностью. Собирает статистику из логов postgres. Но в логи попадают не все запросы.
|
||
- Иметь примеры запросов с параметрами.
|
||
- Для понимания входящих параметров запроса.
|
||
- Необходимо для проверки оптимизаций
|
||
- Вручную собрать более полную статистику. Редко делается, при необходимости.
|
||
- По умолчанию PostgrteSQL использует для сбора статистики только 30k строк из таблицы. Из-за этого статистика может расходиться с реальностью.
|
||
- Уметь читать статистику распределения данных (планировщик). [explain](Профилирование%20запросов%20в%20PostgreSQL.md)
|
||
|
||
При создании индекса важно учитывать [селективность колонки](Селективность%20колонки.md) (разнообразие значений), чем она выше, тем лучше индекс будет выполнять свою задачу.
|
||
|
||
![](Составные%20индексы%20в%20БД.md#^630c7e)
|
||
|
||
- [PostgreSQL: Documentation: 16: CREATE INDEX](https://www.postgresql.org/docs/current/sql-createindex.html)
|
||
|
||
При добавлении индекса происходит блокировка таблицы.
|
||
### Частичный индекс
|
||
Можно создать частичный индекс по условию, который будет покрывать только записи, которые удовлетворяют определенному условию where.
|
||
|
||
```sql
|
||
create index fk_not_null on pgconf(fk_id)
|
||
where fk id is not null;
|
||
```
|
||
|
||
Допустим, исключим из индекса по FK null значения. В этом случае мы не ускорим работу индекса, так как БД достаточно умная, чтобы делать это автоматически. Но это позволит уменьшить размер индекса. Но на больших данных это также может сказать и на производительности.
|
||
|
||
## Заметки
|
||
- Для первичного ключа индекс создается автоматически
|
||
- Можно отключить автоматическое обновление индекса и сделать обновление ручным
|
||
|
||
## Полезные команды
|
||
Расширение pageinspect позволяет изучить структуру индекса (размер страницы, количество страниц и так далее).
|
||
|
||
```sql
|
||
create extension pageinspect
|
||
```
|
||
|
||
Посмотреть сколько раз индекс использовался и когда был последний вызов.
|
||
```sql
|
||
select * from pg_stat_user_indexes
|
||
```
|
||
|
||
Посмотреть размер индекса
|
||
```sql
|
||
select pg_size_pretty(pg_indexes_size('orders'))
|
||
```
|
||
|
||
|
||
Проверить какие индексы существуют для таблицы:
|
||
```sql
|
||
select * from pg_indexes where tablename='table_name';
|
||
```
|
||
|
||
Можно получить мета информацию о дереве индекса:
|
||
```sql
|
||
select * from bt_metap('users_pkey');
|
||
```
|
||
|
||
Можно получить мета информацию о конкретном узле:
|
||
```sql
|
||
select * from bt_page_stats('users_pkey', 3);
|
||
```
|
||
|
||
|
||
## Дополнительные материалы
|
||
Дополнительные заметки
|
||
- [Доклад. Индексы в PostgreSQL. Как понять, что создавать](Доклад.%20Индексы%20в%20PostgreSQL.%20Как%20понять,%20что%20создавать.md)
|
||
|
||
Материалы:
|
||
- [009. B-деревья. Система непересекающихся множеств - М. А. Бабенко - YouTube](https://www.youtube.com/watch?v=KFcpDTpoixo)
|
||
- [Индексы в PostgreSQL — 1 / Хабр](https://habr.com/ru/companies/postgrespro/articles/326096/)
|
||
- [Introduction of B+ Tree - GeeksforGeeks](https://www.geeksforgeeks.org/introduction-of-b-tree/) |