Interview questions. Databases #1
Когда речь заходит о PostgreSQL, индексы – это не просто какой-то дополнительный «плюс», а зачастую ключ к реальной производительности.
Правильный подбор и использование индексов позволяет вашим запросам пробегаться по миллионам строк так, будто их всего десяток. Но в Postgres есть несколько разных типов индексов, и у каждого своя специализация, свой характер. Давайте разбираться детально, а заодно посмотрим на примеры запросов и результаты.
Когда вы начинаете работу с индексами в Postgres, чаще всего в ход идёт B-Tree. Это ваш универсальный боец. Если у вас типичная выборка по равенствам, сравнениям, сортировкам — B-Tree подходит идеально.
Представим, что у нас есть таблица с заказами:
Теперь, когда вы запрашиваете:
Вы увидите, что запрос может использовать индекс. Если без индекса поиск занимал долгое время, с ним задержка может упасть в миллисекунды.
Но что, если у нас вместо целочисленного идентификатора нужно искать по UUID или текстовому полю точно по равенству?
Тут у нас есть Hash-индекс. Он чаще нужен, когда у вас точное сравнение.
Например:
Тут у нас есть Hash-индекс. Он чаще нужен, когда у вас точное сравнение.
Например:
Здесь Hash-индекс может помочь, хотя честно, B-Tree часто настолько хорош, что Hash-индексы — редкость.
Далее идут более интересные индексы: GiST и GIN. GiST (Generalized Search Tree) – это индекс для данных, где классические сравнения по >, < уже не так актуальны.
Геоданные? Диапазоны? Сложные структуры? Тогда GiST.
Например, у нас есть таблица с геокоординатами:
GiST ускорит поиск точек в определённом радиусе. Без него всё бы заняло куда больше времени.
GIN (Generalized Inverted Index) — отличная штука для полнотекстового поиска, массивов, jsonb. Если у вас поле с текстом и вы хотите быстро находить документы, содержащие определённые слова, GIN – ваш выбор.
Пример:
GIN умеет индексировать значения внутри сложных структур. Конечно, вы можете сказать: «Зачем GIN, когда есть Elasticsearch?» Да, Elastic – это отдельный софт, очень мощный. Но тогда вы тащите в инфраструктуру ещё один сервис, а данные нужно будет синхронизировать. Если вы хотите держать всё в одной базе и объёмы не столь гигантские, GIN – отличный вариант.
И напоследок BRIN. Если у вас огромные таблицы, где данные идут по времени или другому упорядоченному признаку, BRIN-индекс может сэкономить тонну места и улучшить скорость. Он хранит минимально-максимальные значения по блокам, а не для каждой строки. Это даёт вам возможность быстро исключать большие куски данных, которые точно не подходят под запрос. BRIN чем-то напоминает подход «укрупнённого» индексирования, похожий по идее на колоночные СУБД (например, ClickHouse), но не стоит путать их напрямую. ClickHouse – это отдельная система с собственной философией хранения и обработки данных. BRIN в Postgres – это просто лёгкий, экономный индекс для отсечения огромных участков данных.
Теперь, как понять, что ваш индекс работает или не работает так, как вы хотели? Юзайте EXPLAIN и EXPLAIN ANALYZE.
Запустите запрос с EXPLAIN:
Вы получите план выполнения: какой индекс используется, какие операции задействованы. Добавьте ANALYZE:
Теперь вы увидите фактическое время и количество строк, прошедших через план. Можно добавить дополнительные опции, например EXPLAIN (BUFFERS), чтобы понять, сколько страниц данных читалось с диска или из памяти, или EXPLAIN (ANALYZE, VERBOSE), чтобы получить ещё более детальный отчёт. Есть и другие флаги, позволяющие глубже копать в производительность вашего запроса.
В итоге, индексы в Postgres — это набор инструментов для самых разных задач. B-Tree подойдёт для большинства случаев. Hash иногда выручит при точном равенстве по ключу. GiST и GIN поднимают уровень сложности, позволяя индексировать сложные или нетривиальные типы данных, а GIN ещё и отличный для полнотекста или вложенных структур. BRIN пригодится, когда объёмы данных настолько велики, что обычные индексы будут слишком тяжёлыми и дорогими.