118 lines
8.5 KiB
Markdown
118 lines
8.5 KiB
Markdown
---
|
||
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)
|
||
|