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

154 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
aliases:
- индексирования
tags:
- зрелость/🌱
date:
- - 2024-03-31
zero-link:
- "[[00 PostgreSQL]]"
parents:
linked:
- "[[Индексы в MySQL]]"
---
Индекс это служебная структура данных, которая позволяет ускорить запросы (поиск, сортировку) к базе данных.
**Польза:**
- Ускоряют запросы: равенство, сравнения, сортировка
- В некоторых случаях позволяют избежать чтения из таблицы. [Покрывающий индекс](Покрывающий%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/)