digital-garden/source/доклады/Доклад. Индексы в PostgreSQL. Как понять, что создавать.md

118 lines
8.5 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.

---
parents:
- "[[Java конференция Joker]]"
- "[[Индекс в PostgreSQL]]"
author:
- "[[Сальников Андрей (Data Egret)]]"
zero-link:
- "[[00 Базы Данных]]"
link: https://www.youtube.com/watch?v=ju9F8OvnL4E
---
## О чем доклад
- Говорится в основном о [OLTP](OLTP.md) нагрузке, про OLAP не будем
- Объемы баз данных от 20Гб до 10Тб
## Заметки
- [PostgreSQL: Documentation: 16: CREATE INDEX](https://www.postgresql.org/docs/current/sql-createindex.html)
- Для первичного ключа индекс создается автоматически
- Профиль нагрузки на реляционную базу данных выглядит следующим образом: 80% запросов это чтение, 20% запросов это запись. Если запросов на запись больше, то возможно реляционная база данных вам не подходит.
- Плюсы индексов
- Ускорение запросов
- Минусы
- Замедление записи в таблицы (80% к 20%). Так как необходимо будет перестраивать индекс при вставке новых значений.
- Дополнительные объемы дискового пространства. Размер индекса в половину размера таблицы считается нормальным и оптимальным
- Усложненное технического обслуживание.
- #todo bloat. индексы пухнуть и переодически их нужно пересоздавать
- Перед созданием индекса стоит провести предварительный анализ. Так как не все индексы полезны, некоторые индексы могут ухудшить ситуацию.
- **Что нужно для создания индекса?**
- Ориентироваться только на продуктовое окружение, так как тестовые окружения не соответствуют реальности.
- Собрать статистику нагрузки на БД от запросов.
- Инструменты для сбора статистики:
- [pg_stat_statements](pg_stat_statements.md) - отличный инструмент
- pgBadger - использовать с осторожностью. Собирает статистику из логов postgres. Но в логи попадают не все запросы.
- Иметь примеры запросов с параметрами.
- Для понимания входящих параметров запроса.
- Необходимо для проверки оптимизаций
- Уметь читать статистику распределения данных (планировщик).
- Представление [pg_stats](Таблица%20статистик%20pg_stats.md).
- Вручную собрать более полную статистику.
- По умолчанию PostgrteSQL использует для сбора статистики только 30k строк из таблицы. Из-за этого статистика может расходиться с реальностью.
- **Типы индексов**
- btree
- Наиболее распространенный тип индексов
- Очень хороший алгоритм работы
- Покрывает 90% задач
- Легко создать ориентируясь на статистику по таблице
- Обслуживает как операции сравнения так и операции равенства
- Позволяет выполнить сортировку
- hash индекс
- Абсолютно бесполезен. Используйте btree.
- Занимает меньше места на диске, чем btree
- Обслуживает только операции равенства.
- Нельзя выполнить сортировку
- gist индекс
- В чистом виде полезен для гео-данных
- Расширения
- pg_trgm - like, ilike, ~, ~* (regexp)
- btree_gits - слодные constrains с интервалами. Позволяет переложить на базу данных задачу по контролю пересечения времени. Например, если нужно создать расписание, и чтобы временные интервалы заданий не пересекались.
- sp_gist индекс
- Нет практических применений в [OLTP](OLTP.md)
- Возможно полезен в научной сфере
- gin индекс
- Может сильно ухудшить время вставки в таблицу
- Хорошо для текстового поиска
- Позволяет ускорить поиск по jsonb
- jsonb_ops - используется по умолчанию. Индексирует все значения jsonb, из-за этого индекс получается больших размеров.
- json_path_ops - заточен на поиск путей в json. То есть позволяет ответить, есть ли такое-то поле в jsonb или его нет.
- brin
- Компактный индекс
- Подходит для упорядоченных данных
## Практика
![](Pasted%20image%2020240331092706.png)
![](Pasted%20image%2020240331092753.png)
- Индекс по первичному ключу занял 1/4 от размера таблицы
- Таблица ссылается сама на себя, но это сделано для удобства доклада. Те же самые выводы распространятся и на связи с другими таблицами.
### Удаляем строку
![600](Pasted%20image%2020240331093028.png)
- В удалении задействован первичный ключ, поэтому используется поиск по индексу
- ==Самый долгий этап это проверка связей с таблицей==
Под капотом для поиска внешних связей мы используем полное сканирование таблицы (Seq Scan).
![600](Снимок%20экрана%202024-03-31%20в%2009.32.34.png)
==Вывод: не забывать создавать индексы на Foreign Key.==
Добавляем индекс на FK и проверяем результат:
![600](Pasted%20image%2020240331093524.png)
Мы получили ускорение в 2055 раз.
#### Смотрим статистику
[Таблица статистик pg_stats](Таблица%20статистик%20pg_stats.md)
![600](Снимок%20экрана%202024-03-31%20в%2009.36.56.png)
В данном случае у нас 92% значений в колонке это null значения.
Основываясь на этой информации мы можем уменьшить размер индекса. Для этого изменим запрос на создание индекса, добавив `where fk_id is not null`.
![600](Pasted%20image%2020240331094502.png)
Таким образом у нас получилось сжать индекс в 14 раз:
![500](Pasted%20image%2020240331095259.png)
### Поиск записей по статусу
Мы находим записи по какому-то статусу.
![300](Pasted%20image%2020240331095959.png)
![600](Pasted%20image%2020240331100144.png)
Часто появляется желание сделать индекс по полю статуса:
![600](Снимок%20экрана%202024-03-31%20в%2010.07.02.png)
По факту мы индексируем поле, которое имеет небольшую [селективность](Селективность%20колонки.md). Такой индекс не эффективный.
Хороший вариант в данном случае:
![600](Снимок%20экрана%202024-03-31%20в%2010.13.39.png)
Почти идеальный:
![600](Снимок%20экрана%202024-03-31%20в%2010.15.06.png)
![500](Pasted%20image%2020240331101612.png)