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

118 lines
8.5 KiB
Markdown
Raw Normal View History

2024-06-13 21:01:37 +03:00
---
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. индексы пухнуть и переодически их нужно пересоздавать
- Перед созданием индекса стоит провести предварительный анализ. Так как не все индексы полезны, некоторые индексы могут ухудшить ситуацию.
- **Что нужно для создания индекса?**
- Ориентироваться только на продуктовое окружение, так как тестовые окружения не соответствуют реальности.
- Собрать статистику нагрузки на БД от запросов.
- Инструменты для сбора статистики:
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. Но в логи попадают не все запросы.
- Иметь примеры запросов с параметрами.
- Для понимания входящих параметров запроса.
- Необходимо для проверки оптимизаций
- Уметь читать статистику распределения данных (планировщик).
- Представление [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)