--- 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)