← Назад к вопросам

Какой лучше использовать индекс для запроса на получение значений, где столбец меньше или больше какого-то значения: хеш или B-tree?

2.0 Middle🔥 82 комментариев
#Базы данных#Производительность и оптимизация

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Выбор между B-деревом и хеш-индексом для запросов с диапазоном

Для запросов с условиями WHERE column < value или WHERE column > value (диапазонные запросы) однозначно лучше использовать B-дерево (или его модификацию B+tree, которая чаще применяется в СУБД). Хеш-индекс в данной ситуации не подходит в принципе.

Подробное объяснение

1. Принципиальная разница в структуре и доступе

Хеш-индекс основан на хеш-таблице. Он работает по следующему принципу:

-- Хеш-индекс эффективен ТОЛЬКО для точного совпадения
SELECT * FROM table WHERE column = 'exact_value';
  • Вычисляет хеш-функцию от искомого значения.
  • По полученному хешу находит соответствующий "bucket" (сегмент), в котором хранятся указатели на строки с этим конкретным значением.
  • Не поддерживает упорядочивание данных. Элементы в хеш-таблице расположены в произвольном порядке, определяемом хеш-функцией.

B-дерево — это сбалансированное отсортированное дерево:

-- B-дерево эффективно для диапазонов, префиксов и сортировки
SELECT * FROM table WHERE column > 100 AND column < 500;
SELECT * FROM table ORDER BY column;
SELECT * FROM table WHERE column LIKE 'prefix%';
  • Значения в листовых узлах отсортированы.
  • Обход дерева позволяет быстро находить первое подходящее значение в диапазоне, а затем последовательно читать следующие значения, пока условие не нарушится.

2. Почему B-дерево эффективно для диапазонных запросов?

Алгоритм работы B-дерева для запроса WHERE column > X:

  1. Быстрый поиск точки начала: За O(log n) операций находится первое значение, удовлетворяющее условию column = X (или ближайшее большее, если точного совпадения нет).
  2. Последовательный обход в порядке возрастания: Поскольку листовые узлы связаны ссылками (в B+tree) и значения отсортированы, СУБД просто читает данные последовательно от найденной стартовой точки до конца диапазона или таблицы. Это крайне эффективная операция.

Критически важно: B-дерево хранит данные в отсортированном виде, что является фундаментальным требованием для эффективного выполнения операторов >, <, BETWEEN, ORDER BY.

3. Почему хеш-индекс бесполезен для диапазонов?

Для выполнения запроса WHERE column > X с хеш-индексом СУБД не имеет другого выбора, кроме как:

  1. Вычислить хеши для всех возможных значений, больших X (что невозможно, так как множество значений непрерывно).
  2. Просканировать всю таблицу последовательно (Full Table Scan), проверяя условие для каждой строки. Хеш-индекс в этом процессе не участвует, так как не может предоставить ни сортировки, ни механизма обхода "следующих" значений.

Хеш-индекс — это структура данных для быстрого точечного доступа (point query), а не для работы с диапазонами (range query).

Практические выводы и рекомендации

  • Для диапазонных запросов (<, >, BETWEEN), а также для сортировки (ORDER BY) и запросов по префиксу строк (LIKE 'abc%') используйте B-дерево. Это его основная и сильнейшая сторона.
  • Хеш-индекс стоит рассматривать только для специализированных случаев:
    *   Частые запросы на **точное совпадение** (`=`) по уникальным или почти уникальным ключам.
    *   Таблицы, которые **никогда** не используются для диапазонных запросов или сортировки по этому столбцу.
    *   Часто он используется для `IN-memory` таблиц или кешей (например, в MySQL `MEMORY` storage engine).

Пример в контексте PostgreSQL

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

-- Создание индекса, который будет работать для диапазонов
CREATE INDEX idx_orders_amount_btree ON orders(amount); -- По умолчанию B-tree

-- Эффективный запрос с использованием B-tree индекса
EXPLAIN ANALYZE SELECT * FROM orders WHERE amount > 1000 AND amount < 5000;
-- В плане будет видно: "Index Scan using idx_orders_amount_btree"

-- Создание хеш-индекса (используйте с большой осторожностью!)
CREATE INDEX idx_orders_hash ON orders USING HASH (order_code);

-- Этот запрос сможет использовать хеш-индекс
SELECT * FROM orders WHERE order_code = 'ABC123';

-- А этот запрос - НЕ СМОЖЕТ. Выполнится полное сканирование.
SELECT * FROM orders WHERE order_code > 'ABC100';

Заключение

Выбор между B-деревом и хеш-индексом для операций сравнения (<, >) не является предметом дискуссии — это B-дерево. Хеш-индексы имеют узкую нишу применения для операций точного равенства в ущерб всем другим типам запросов. В подавляющем большинстве реальных сценариев, где столбец потенциально может участвовать не только в поиске по точному значению, но и в фильтрации по диапазону, сортировке или группировке, B-дерево является безусловно предпочтительным и универсальным выбором.