Почему индексы в базах данных устроены как B-дерево?
- Что такое B-дерево и B+-дерево?
- Почему в базе не используют бинарное дерево поиска?
- Сколько чтений с диска нужно, чтобы найти строку по индексу?
B-дерево — сбалансированное дерево с широкими узлами: в узле сотни ключей, узел = страница на диске (8–16 КБ). Высота 3–4 даже для миллиардов строк — значит, 3–4 чтения страницы.
- Бинарное дерево дало бы высоту ~30 и столько же случайных чтений
- Вставка в полный узел делит его пополам, дерево растёт от корня — всегда сбалансировано
- B+-дерево: данные только в листьях, листья связаны — быстрый диапазонный поиск и ORDER BY
А ещё Поэтому индекс помогает в =, <, >, BETWEEN, префиксе LIKE 'abc%' и сортировке
Подробно
Диск (и даже SSD) читает не байты, а страницы, и случайное чтение дорогое. Значит, структура поиска должна минимизировать число прочитанных страниц.
Бинарное дерево поиска для миллиарда ключей имеет высоту не меньше 30; каждый узел — отдельная страница, итого ~30 случайных чтений. И даже сбалансированное (AVL, красно-чёрное) плохо ложится на страницы.
B-дерево делает узел размером со страницу. В странице 8 КБ помещаются сотни ключей с указателями — коэффициент ветвления 200–500. Тогда:
- 2 уровня — до 250 тыс. ключей;
- 3 уровня — до 60 млн;
- 4 уровня — до 15 млрд.
Корень и верхние уровни почти всегда в кэше, поэтому поиск — 1–2 реальных чтения. Внутри узла ключи отсортированы, и нужный указатель находится бинарным поиском.
Вставка. Ключ кладётся в нужный лист. Если лист переполнен, он делится пополам, а средний ключ поднимается в родителя; если переполнился родитель — делится и он. Корень делится — появляется новый корень, высота растёт на 1 для всех листьев сразу. Поэтому дерево всегда идеально сбалансировано. Удаление может сливать недозаполненные узлы.
B+-дерево — вариант, который используют почти все СУБД: во внутренних узлах только ключи-разделители, сами записи (или ссылки на них) — в листьях, а листья связаны в список. Диапазонный запрос находит начало и идёт по листьям подряд — это и BETWEEN, и ORDER BY без сортировки.
Что из этого следует для запросов:
- индекс работает для равенства, диапазонов, сортировки и префикса строки (
LIKE 'ab%'), но не дляLIKE '%ab'и не для функции от колонки без функционального индекса; - составной индекс
(a, b)отсортирован сначала по a — поэтому поиск по одному b его не использует; - вставка случайных ключей (UUIDv4) раскидывает записи по всем листьям: больше разделений, кэш хуже — отсюда интерес к UUIDv7 и автоинкременту;
- каждый индекс — отдельное дерево, которое нужно обновлять при записи.
В InnoDB таблица сама хранится как B+-дерево по первичному ключу (кластерный индекс), а вторичные индексы хранят первичный ключ. В PostgreSQL таблица — куча, а индексы ссылаются на физический адрес строки.
Пример
Таблица на 100 млн строк, ключ bigint (8 байт) + указатель (6 байт),
страница 8 КБ → ~500 ключей на узел.
log_500(100 000 000) ≈ 2,96 → 3 уровня: корень → внутренний узел → лист.
Корень и внутренние узлы в памяти — поиск = 1 чтение листа.Что хотят услышать
- Связь узла со страницей диска и высокий коэффициент ветвления.
- Оценка высоты и числа чтений.
- Вставка с разделением узлов, рост от корня, баланс.
- B+-дерево: данные в листьях, связанные листья, диапазоны.
- Практические выводы для запросов и составных индексов.
Частые ошибки
- «B — значит binary».
- Считать, что поиск по индексу — O(1), как в хеш-таблице.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✗B-дерево — это сбалансированное двоичное дерево: в каждом узле один ключ, а высота log₂n ≈ 30 для миллиарда строк, что и даёт быстрый поиск
- ✗B-дерево перестраивается вручную администратором
- ✓Широкие узлы размером со страницу диска дают высоту 3–4 даже для миллиардов строк — мало чтений страниц
- ✗В B+-дереве данные хранятся только во внутренних узлах
Что спросят дальше
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.