28 августа 2024 6638
В продолжение серии статей об устройстве системы управления базами данных (СУБД) PostgreSQL (раз, два) смотрим, как ускорить выполнение запросов к базе данных с помощью индексов.
Привет, Хабр! Меня зовут Артур Титаев, я аналитик департамента проектирования и разработки IBS. Недавно наша команда занималась масштабным импортозамещением компонентов системы поддержки принятия решений для крупного российского заказчика. После переезда с Oracle и MySQL на PostgreSQL мы определили, что время выполнения SQL-запросов для показателей хозяйственно-экономической деятельности клиента в PostgreSQL заметно больше, чем время выполнения тех же запросов для тех же показателей в Oracle. Для «тяжелых» показателей разница во времени выполнения запроса могла достигать 20–30 минут. И это несмотря на то, что база данных Oracle не была проиндексированной!

Вопрос о применении индексов в PostgreSQL — особой структуры данных, которая ускоряет выборку из таблицы, — встал ребром, и я принялся за его изучение. Раньше мне доводилось сталкиваться только с простейшими индексами, так что на полноценное погружение в тему у меня ушло немало часов. Чтобы сэкономить вам время, я собрал ключевую теорию про индексирование в этой статье.

Устройство баз данных и таблиц

Чтобы понять, как работают индексы, посмотрим, как устроены базы данных.

  Вот так сейчас выглядит наш кластер:


Файлы данных кластера лежат в директории data. Для каждой базы данных есть своя дочерняя папка в data/base, а для каждой таблицы и индекса выделяется отдельный файл. Такой файл таблицы называется Heap File. Он содержит список неупорядоченных записей различной длины и не должен превышать 1GB. Если размер файла превышает 1GB, то создается следующий. Соответственно, наша таблица в базе данных будет храниться уже в двух или более файлах. Сама же таблица состоит из массива страниц. Другими словами, страница — это строки таблицы, а файл — это таблица в базе данных.

Каждая страница содержит:
✔️ заголовок;
✔️ строки, состоящие из заголовка строки и самой строки;
✔️ ссылки на строки (ctid) — метаданные, состоящие из номера страницы и индекса, с их помощью СУБД может быстрее обращаться к необходимым данным.

Картинка для наглядности:


Вместе с файлом таблицы на сервере лежит файл FSM — Free Space Map. Поскольку максимальный размер страницы — 8КБ, файл FSM помогает серверу сразу понять, куда можно сохранить данные, вместо того, чтобы сканировать все страницы таблиц в поисках свободного места. Важно, что FSM не обновляется при каждом обновлении или удалении строк в таблице. В этом есть своя логика: сохранение старой версии таблицы нужно для корректной работы механизма параллельного доступа, чтобы разные пользователи могли одновременно использовать СУБД.

Механизм TOAST

Сервером запрещается хранение значений строки в разных страницах. В таком случае мы используем механизм TOAST — The Oversized-Attribute Storage Technique. Каждая таблица имеет ассоциированную с ней TOAST-таблицу, в которой хранятся большие значения, нарезанные кусочками по 2 КБ. В столбце нашей исходной таблицы просто помещается ссылка на место в TOAST-таблице, где хранятся реальные значения.



Подробнее о механизме TOAST можно почитать в этом лонгриде от разработчика PostgreSQL.

Fill Factor

Теоретическая база выше должна помочь понять, что такое и как устроен Fill Factor — параметр для индексов в SQL. При создании или перепостроении индекса мы можем задать этот параметр и указать серверу, какой процент каждой страницы мы будем заполнять. По умолчанию это значение равно 100%, то есть Fill Factor пытается забить всё место до предела. Но этот коэффициент не всегда хорош. Если я заполняю все свои страницы до предела, а потом, используя какой-нибудь сложный индекс, пытаюсь вставить строку на эту страницу, то она просто-напросто не поместится. В таком случае серверу придется выполнить довольно много операций для того, чтобы эту строку вместить.

В то же время, если использовать классический кластеризованный индекс с увеличивающимся значением ID и вставлять новые строки в конец списка, оставлять большое количество пустого пространства на страницах данных, делая Fill Factor маленьким, тоже неэффективно, поскольку это также будет негативно сказываться на производительности. Наши данные будут более распределены, и нам придется: а) использовать больше страниц в памяти; б) использовать больше места в кэше, что плохо.

Вывод: значение Fill Factor должно быть тем меньше, чем больше и чаще происходят изменения в наших данных.


Что еще важно знать про Fill Factor:

✔️ нельзя применять один и тот же фактор заполнения для всех индексов;

✔️ Fill Factor применяется только к индексам, а не ко всем таблицам;

✔️ не применяется к LOB-страницам, то есть к большим данным, которые хранятся уже не в самих таблицах, а в ассоциированных с ними TOAST-таблицах;

✔️ не влияет на новые страницы, вставленные в конце индекса;

✔️ будучи нетривиальным параметром, используется только опытными базистами.


VACUUM

Для очистки старых ненужных версий строк используется команда VACUUM. Строго говоря, она не возвращает операционной системе память, то есть физически не удаляет такие строки, а лишь отмечает отрезки памяти, которые мы можем перезаписать. А вот полную дефрагментацию таблицы можно осуществить с помощью команды VACUUM FULL. Вместе с файлом таблицы на сервере также лежит файл VM — Visibility Map. Как раз он и показывает наличие/отсутствие «протухших» версий строк. Если в файле хранится значение «1», значит, страница не содержит неактуальные версии строк.


Фрагментация данных нарастает, если не обслуживать базу данных, поэтому необходим периодический запуск VACUUM. Для активно обновляемых баз данных VACUUM рекомендуется проходить каждую ночь. А вот VACUUM FULL лучше использовать только в том случае, когда удалено очень много данных относительно самой таблицы — порядка 30–40%.


Команда VACUUM ANALYZE собирает статистику о содержимом в таблицах и сохраняет результат в специальном системном каталоге. Полученную статистику планировщик запросов может использовать для того, чтобы определить для себя наиболее эффективный план выполнения запросов. VACUUM ANALYZE можно использовать с параметром для определенной таблицы в базе данных.


Autovacuum — бэкграунд-процесс, который осуществляет все операции по очистке и маркировке «протухших» строк автоматически. По умолчанию он всегда включен, и отключать его не рекомендуется.


Индексы: теоретическая база

А теперь переходим непосредственно к индексам.


Индекс — это объект базы данных, который можно создать и удалить, как и любую таблицу. Индексы создаются для столбцов таблиц и даже для представлений. Они позволяют искать необходимые значения без полного перебора. Приведу простую аналогию: когда нам нужно найти в магазине, скажем, книгу Стивена Хокинга, мы идем к стеллажам с надписью «Научпоп». Примерно так же работают индексы.


По сути, индексы можно назвать методом доступа к данным. Они устанавливают соответствие между ключом, то есть значением столбца, который мы индексируем, и строками таблицы, в которых этот ключ встречается. С помощью индексного сканирования мы можем быстро найти те строки, в которых есть данный ключ.


От того, сколько записей фильтрует запрос, зависит, будет ли использован индекс или полное сканирование таблицы. Как правило, если запрос фильтрует небольшое число записей относительно самой таблицы, например, 100 строк в таблице на миллион строк, то мы используем индекс.


Что еще важно знать:

✔️ при любом обновлении проиндексированных данных в таблице индексы также нужно перестраивать;

✔️ индексы требуют затрат на поддержание, так как имеют свою структуру;

✔️ индексы имеют собственные ограничения, в том числе и по поддерживаемым операциям.


Методы сканирования

Методы сканирования — это то, каким образом система будет выполнять наш запрос к базе данных. Метод сканирования определяет оптимизатор, который ищет наиболее эффективный план выполнения запроса.

Существует четыре основных метода сканирования:

1. Последовательное сканирование — sequential scan: просто перебор каждой строки; происходит по умолчанию.

2. Индексное сканирование — index scan: используется при большом наборе проиндексированных данных; потенциально в результирующий набор попадет сравнительно малое количество строк.

3. Исключительно индексное сканирование — index only scan: некоторые индексы вместе с идентификаторами строк хранят сами значения, и этот метод позволяет читать индекс, не обращаясь к таблицам с данными, и забирать результат прямо из индекса. Исключительно индексное сканирование эффективнее простого индексного сканирования. Но здесь есть нюанс: мы обязательно должны посмотреть Visibility Map, чтобы выяснить актуальность записей. Только в том случае, если страница не содержит недействительных строк, мы можем применять исключительно индексное сканирование.

Сканирование по битовой карте — bitmap scan: применяется при относительно большой выборке, когда она слишком большая для того, чтобы мы применяли индексное сканирование, но в то же время не настолько большая, чтобы мы применяли обычное последовательное сканирование каждой строки. При увеличении выборки увеличивается вероятность того, что мы будем читать одни и те же страницы множество раз, и в таких случаях мы используем bitmap scan. Преимущество метода в том, что он работает при поиске более чем по одному индексу.

Типы индексов

PostgreSQL поддерживает разные типы индексов для разных задач, в частности:

✔️ B-Tree, он же Balanced Tree, — сбалансированное дерево;

✔️ Hash — хеш-индекс, в отличие от B-Tree, хранит целые числа, они же хеш-коды, а не значения;

✔️ и другие.


Если в pgAdmin написать команду SELECT amname FROM pg_am, то мы сможем посмотреть, какие типы индексов доступны на сервере. Примерно в 95% случаев используется тип индексов B-Tree, так как он применим к любым данным, которые можно отсортировать, и покрывает широчайших класс задач. Остальные типы индексов используются только в исключительных ситуациях, поэтому останавливаться на них подробно не буду.


B-Tree

Когда мы просто создаем индекс командой CREATE INDEX index_name ON table_name (column_name), то по умолчанию создается индекс именно этого типа. B-Tree поддерживает операторы <, >, <=, >=, = и LIKE (‘abc%’). Оператор LIKE (‘%abc’), напротив, не поддерживает. B-Tree индексирует запрос из NULL и NOT NULL.


Сложность поиска по этому индексу логарифмическая. Если наш массив данных отсортирован, мы можем проверить и найти какое-то конкретное нужное нам значение методом деления пополам, то есть прийти к результату через logN элементов проверки. Например, в таблице из восьми строк мы таким алгоритмом найдем нужное значение с помощью трех итераций:




Когда задаем PRIMARY KEY, UNIQUE или просто задаем CREATE INDEX, по умолчанию будет построен B-Tree.

Сравнение типов B-Tree

Кластеризованный

Некластеризованный

Порядок хранения

✔️ Сортирует и хранит данные по правилу сортировки; 

✔️ использует первичный ключ для структуризации данных в таблице; 

✔️ всегда изменяет физический порядок хранимых данных

✔️ Не упорядочивает физическое хранение, используя метки для доступа к данным; 

✔️ создает свою отдельную структуру данных, которая не зависит от фактической таблицы, для которой он строится

Конечные листья индекса

Используются для хранения

Не используются для хранения

Место на диске

Занимает много места

Занимает мало места

Скорость доступа

Быстрый

Медленный

Дополнительное место на диске

Не нужно

Необходимо, так как индекс хранится отдельно от физических данных таблицы

Простота использования

Не требует явного объявления и создается по умолчанию при определении ключа, то есть в принципе легче в использовании — в том числе в плане синтаксиса

Требует явного определения; содержит в себе только те столбцы таблицы, по которым определен, поэтому системе запросов нужна дополнительная операция для того, чтобы получить данные из индекса

Сортировка данных

Возможна

Невозможна

Создание нескольких индексов на одну таблицу

Невозможно

Возможно

Специфика

Может повысить производительность при извлечении требуемых данных

Применяется только к неключевым столбцам, которые используются в запросах join


Как видно из таблицы, у каждого из подвидов B-Tree есть свои преимущества и недостатки. В целом некластеризованные индексы довольно полезны при очень больших наборах данных, потому что они не меняют физический порядок хранимых данных. Подтип некластеризованного индекса — cover index, покрывающий индекс — это индекс, которого достаточно для ответа на запрос вообще без обращения к самой таблице, что, безусловно, быстрее, чем обращение к таблице через обычный индекс. Однако и злоупотреблять этим тоже не стоит: когда мы включаем в покрывающий индекс всё больше и больше информации, он сам становится тяжелее и больше и время поиска по нему увеличивается.

EXPLAIN

Перед тем как построить индекс, нам нужно понять, какой тип индекса использовать. Команда EXPLAIN (SELECT...) позволяет посмотреть план выполнения запроса при использовании того или иного индекса. В свою очередь, команда EXPLAIN ANALYZE (SELECT...) прогоняет запрос и показывает не только план, но и сам запрос, благодаря чему мы можем определить наиболее эффективный индекс для использования.
Подробнее о команде EXPLAIN советую почитать здесь.

Когда индексы не нужны

В отдельных случаях индексы не принято использовать в принципе. К ним относятся:
✔️ небольшие таблицы — поскольку методы индексного сканирования и последовательного сканирования практически не будут отличаться друг от друга по времени;
✔️ таблицы с частыми массовыми изменениями UPDATE и INSERT — потому что индексы тоже требуют перестройки, и это будет неэффективно;
✔️ часто обрабатываемые столбцы;
✔️ столбцы с большим количеством значений NULL;
✔️ столбцы с типами данных image, text или varchar(max) — индексация больших тяжелых данных займет слишком много времени.

Заключение

Надеюсь, эта статья сэкономила вам время на первое погружение в тему индексов в PostgreSQL. Главное, помнить, что цель индексирования — ускорить выполнение нашего запроса к базе данных. Если мы пытаемся применить индекс к неподходящему виду данных или используем некорректный тип индекса, то время выполнения запроса рискует, наоборот, увеличиться. Так что к тонкому вопросу индексирования нужно подходить смело, но с умом.

О практической стороне индексирования баз данных в PostgreSQL я расскажу в другой статье. А пока задавайте в комментариях свои вопросы по индексам — постараюсь на всё ответить.

Оригинал статьи
читайте на Хабре.

Последние статьи в блоге

Саммари вебинара «ИИ-инструменты в работе архитектора ПО»

Дмитрий Овчаренко, технический директор с 15-летним опытом в архитектуре ПО, на сквозном примере стартапа — платформы для кондитеров — показал, как ИИ помогает архитектору ускорить работу на всех этапах: от чистого листа до готовых артефактов для команды.

Новости
07 августа 2026

Контроль качества ИИ-систем: от теории к практике

На результаты внедрения искусственного интеллекта в компаниях влияет сложный комплекс факторов. Для получения эффективного решения необходим контроль его качества и устранение узких мест на протяжении всей работы над проектом. О том, как этого добиться, рассказали заместитель директора центра перспективных разработок IBS Денис Воденеев и старший аналитик группы Data Science IBS Илья Гайдуков.

Новости
05 августа 2026

Саммари вебинара «Искусственный интеллект для бизнес-аналитика. Автоматизация для усиления экспертизы»

Максим Охманюк, эксперт с 25-летним опытом в IT, бизнес-анализе и управлении проектами, разобрал, как ИИ становится инструментом усиления аналитика, а не его заменой.

Новости
31 июля 2026

Как мы проектировали систему оценки ИТ-персонала для федерального ритейлера

В Учебном центре IBS мы разрабатываем методологию оценки персонала под задачи конкретного клиента. В крупной федеральной розничной сети с десятками ИТ-ролей и разрозненными критериями уровней специалистов это потребовало создания единой системы с нуля. Рассказываем, как это было.

28 июля 2026

Будущее разработки ПО: от кода к оркестрации агентов

Мультимодальные интерфейсы, внедрение ИИ-инструментов, новые подходы к анализу данных и принятию решений в компаниях уже активно меняют процесс разработки программного обеспечения. О том, как может эволюционировать создание ПО в недалеком будущем, рассказал Максим Ковтун, управляющий партнер «Разработка и тестирование» IBS.

Новости
23 июля 2026

IBS запускает независимую сертификацию для тестировщиков ПО

Центр сертификации IBS инициировал новую программу независимой оценки квалификации для тестировщиков программного обеспечения. Сертификация IBS позволяет ИТ-специалистам систематизировать знания, подтвердить соответствие единому стандарту качества и повысить конкурентоспособность на рынке труда.

21 июля 2026

Внедрение BI-систем: почему проект может не дать результатов

Реализация системы бизнес-аналитики (BI) может пройти технически гладко, но не принести ожидаемого эффекта компании. Причина обычно не в самой платформе, а в организации работы над проектом. Начальник отдела витрин данных и аналитики IBS Анна Филиппова поделилась взглядом на то, почему возникают такие ситуации и как их избежать.

17 июля 2026

Саммари вебинара «Проектирование высоконагруженной системы на примере агрегатора авиабилетов»

Алексей Додонов, эксперт с 20-летним опытом в ИТ, на сквозном кейсе разобрал эволюцию архитектуры стартапа по продаже авиабилетов — от монолита до распределённой системы, и как команда решала проблемы производительности на каждом этапе.

16 июля 2026

Бесплатный вебинар «Результативный ИИ в бизнесе: как внедрять безопасно, измеримо и с реальной пользой»

Искусственный интеллект — это уже не просто тренд, а рабочий инструмент. Но как перейти от пилотов и экспериментов к системному процессу с понятными метриками и управляемыми рисками?

Новости
03 июля 2026

ИИ в бизнесе: почему экономия на зарплате не всегда равна прибыли

Внедрение ИИ в корпоративную среду стало рутинной задачей для многих ИТ-директоров и руководителей проектов. Однако первые волны оптимизма уже столкнулись с суровой реальностью.

Жизнь компании
18 июня 2026

Саммари вебинара «Техсобес на Java: как системный подход и работа с ИИ превращают стресс в оффер»

Владимир Низов, технический директор с 10-летним стажем и эксперт Учебного центра IBS, рассказал, почему кандидаты проваливают технические интервью и как этого избежать. Отдельно разобрал работу с ИИ. Главное: заучивать тысячи страниц не нужно. Достаточно освоить индексный подход и единый паттерн системного дизайна. А ИИ воспринимать как инструмент с чёткими ограничениями.

Новости
09 июня 2026

Опыт развертывания корпоративной/ведомственной ИИ-инфраструктуры

Разговор о проблемах развертывания ИИ-инфраструктуры часто ведется на макроуровне: дефицит вычислительных мощностей, стоимость ускорителей, зависимость от внешних поставщиков, регуляторные ограничения. Все это важно, но если посмотреть на ситуацию глазами специалиста, которому предстоит решить эту задачу, вопрос становится более прикладным: как развернуть корпоративную ИИ-инфраструктуру, чтобы она не превратилась в дорогой, трудноуправляемый и слабо загруженный набор серверов?

Новости
02 июня 2026

«Аниматор с провалами памяти»: 6 ограничений ИИ, которые не дают вам писать качественный код

Вы когда-нибудь просили ИИ написать метод на Spring Boot, получали красивый, идеально отформатированный код, а он не работал? Потом вы копали глубже и находили, что нейросеть использовала RestTemplate вместо WebClient, забыла про @Transactional, а в методе с @PreUpdate пыталась изменить данные, которые уже ушли в SQL. И вы думали: «Ну, нейросеть же глупая». Нет. Не глупая. Она просто пишет код не как человек.

Новости
28 мая 2026

Роль и место России в мировой гонке в сфере ИИ

По масштабу амбиций и геополитическому значению гонку в сфере искусственного интеллекта все чаще сравнивают с космической гонкой эпохи холодной войны. Соревнование разворачивается одновременно по нескольким осям: вычислительные мощности, данные, кадры, модели и регулирование. В настоящее время ни одну из мировых держав нельзя назвать ведущей по всем направлениям, что оставляет возможность для разных подходов и стратегий в достижении лидерства. О положении России в этом глобальном соревновании, ее стратегических целях, инфраструктурных ограничениях и потенциале для развития рассказывает Денис Воденеев, заместитель директора центра перспективных разработок IBS.

Новости
21 мая 2026

Систематизация ИИ-компетенций: курсы под роли, карты эффективности и модули в комплексных программах

Учебный центр IBS систематизировал подход к развитию навыков работы с искусственным интеллектом. Хаотичное использование нейросетей, как показала практика, не даёт измеримого эффекта. Новое направление построено так, чтобы ИИ решал конкретные бизнес-задачи, а не просто ускорял рутину.

Новости
18 мая 2026

Как защитить бизнес и данные при внедрении ИИ

Искусственный интеллект способен резко расширить возможности развития бизнеса, однако просчеты при внедрении подобных систем могут обернуться серьезными убытками.

Новости
13 мая 2026

Искусственный архитектор: как нейросети справляются с проектированием ПО

В этой статье расскажем про большие языковые модели в приложении к работе архитектора ПО. Вместе мы посмотрим, насколько хорошо GPT понимает ИТ-архитектуру и сможет ли уже сегодня заменить архитектора. Пора разобраться, насколько глубоко ИИ может встроиться в рабочие процессы архитектора ПО — и стоит ли ему там оставаться.

Новости
24 апреля 2026

Бабушка с долгом в полмиллиона, однопоточное ядро и другие грабли: как не повторить чужие архитектурные ошибки

Любая система рано или поздно проверяется на прочность: нагрузкой, ростом бизнеса или человеческим фактором. Именно в эти моменты всплывают решения, которые казались безобидными на старте. Ниже — реальные кейсы из практики, где небольшие архитектурные допущения со временем превращались в ощутимые проблемы. Разберем, какие сигналы можно было заметить сразу и что стоит учитывать, чтобы не повторить эти сценарии в своих проектах.

Новости
16 апреля 2026

Как защитить информацию в приложениях, использующих ИИ

Представим, что системы контроля и анализа транзакций в банке начинают игнорировать 30% мошеннических операций. Система управления энергосетью выводит из строя ключевой узел подачи электроэнергии в город. Чат-бот службы поддержки начинает массово раскрывать персональные данные клиентов. К сожалению, это новая реальность, с которой может столкнуться любая компания, интегрирующая ИИ-системы в бизнеспроцессы.

Новости
08 апреля 2026

Java без розовых очков: какие знания отделяют грейды

Почти каждый разработчик рано или поздно задается вопросом: «Я уже Middle или все еще уверенный Junior?» Опыт растет, задач становится больше, стек шире — но вместе с этим появляется и иллюзия, что раз ты пишешь на Java каждый день, значит, язык знаешь.

Новости
23 марта 2026

Нужна помощь? Оставьте заявку, и мы свяжемся с вами в ближайшее время

Согласен получать на e-mail информационные рассылки о новостях Учебного центра IBS
Корпоративное обучение Бесплатные семинары Оценка персонала Сертификация О нас Стать тренером Блог Личный кабинет
Пользователь только что записался на курс ""
Спасибо!
Форма отправлена успешно.