digital-garden/_inbox/Индекс в PostgreSQL.md

154 lines
10 KiB
Markdown
Raw Normal View History

2024-06-13 21:01:37 +03:00
---
aliases:
- индексирования
tags:
- зрелость/🌱
date:
- - 2024-03-31
zero-link:
- "[[00 PostgreSQL]]"
parents:
linked:
2024-07-02 19:33:28 +03:00
- "[[Индексы в MySQL]]"
2024-06-13 21:01:37 +03:00
---
Индекс это служебная структура данных, которая позволяет ускорить запросы (поиск, сортировку) к базе данных.
**Польза:**
- Ускоряют запросы: равенство, сравнения, сортировка
- В некоторых случаях позволяют избежать чтения из таблицы. [Покрывающий индекс](Покрывающий%20индекс.md).
- Через них можно делать constraints (UNIQUE, FOREIGN KEY)
- Специальные оптимизации?
**Накладные расходы:**
- Дополнительные объемы дискового пространства для хранения индекса. Размер индекса в половину размера таблицы считается нормальным и оптимальным
- Обновляются при модификации данных, на что требуется время и ресурсы. Замедление записи в таблицы (80% к 20%). Так как необходимо будет перестраивать индекс при вставке новых значений.
- Усложненное технического обслуживание. Индексы пухнут и переодически их нужно пересоздавать
**Когда индексы не нужны?**
2024-06-17 18:42:04 +03:00
- Малая [Селективность колонки](Селективность%20колонки.md).
- Большие накладные расходы на поддержание индекса.
2024-06-13 21:01:37 +03:00
- Когда индекс не используется вовсе.
**Когда индексы не работают?**
2024-06-17 18:42:04 +03:00
- В условии используется вычисляемое выражение: `WHERE counter + 1 = 46`
2024-06-13 21:01:37 +03:00
- Если будет отобрано слишком много записей.
- Из агрегирующих функций только `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).
- Инструменты для сбора статистики:
2024-06-17 18:42:04 +03:00
- [pg_stat_statements](pg_stat_statements.md) - отличный инструмент
2024-06-13 21:01:37 +03:00
- pgBadger - использовать с осторожностью. Собирает статистику из логов postgres. Но в логи попадают не все запросы.
- Иметь примеры запросов с параметрами.
- Для понимания входящих параметров запроса.
- Необходимо для проверки оптимизаций
- Вручную собрать более полную статистику. Редко делается, при необходимости.
- По умолчанию PostgrteSQL использует для сбора статистики только 30k строк из таблицы. Из-за этого статистика может расходиться с реальностью.
- Уметь читать статистику распределения данных (планировщик). [explain](Профилирование%20запросов%20в%20PostgreSQL.md)
При создании индекса важно учитывать [селективность колонки](Селективность%20колонки.md) (разнообразие значений), чем она выше, тем лучше индекс будет выполнять свою задачу.
2024-06-17 18:42:04 +03:00
![](Составные%20индексы%20в%20БД.md#^630c7e)
2024-06-13 21:01:37 +03:00
- [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/)