Пошук уроків, статей та іншого контенту
З’ясуєте, коли Hash Index підходить для точного порівняння та чим він відрізняється від B-tree.
Hash Index — це індекс, який зберігає значення у вигляді хешів. Хеш-функція перетворює значення на число, а це число визначає, у якій частині індексу шукати запис.
Такий індекс найкраще підходить для запитів із точним порівнянням:
WHERE email = 'olena@example.com'Hash Index не призначений для пошуку діапазонів або сортування.
Синтаксис:
CREATE INDEX назва_індексу
ON назва_таблиці
USING hash (назва_стовпця);Приклад:
CREATE TABLE users (
id integer GENERATED ALWAYS AS IDENTITY,
email text NOT NULL,
name text NOT NULL
);
CREATE INDEX users_email_hash_idx
ON users
USING hash (email);Тепер PostgreSQL має Hash Index для стовпця email.
Hash Index може допомогти PostgreSQL знайти рядки за точним значенням:
SELECT id, name
FROM users
WHERE email = 'olena@example.com';Індекс підходить саме для умови з оператором =. Наприклад:
WHERE email = 'olena@example.com'А ось такі умови не є типовим призначенням Hash Index:
WHERE email > 'olena@example.com';
WHERE email LIKE 'olena%';
ORDER BY email;Hash Index не зберігає значення в упорядкованому вигляді, тому не може ефективно виконувати пошук за діапазоном або повертати рядки в потрібному порядку.
Для перевірки використання індексу застосовують EXPLAIN.
CREATE TABLE users (
id integer GENERATED ALWAYS AS IDENTITY,
email text NOT NULL,
name text NOT NULL
);
INSERT INTO users (email, name)
SELECT
'user' || number || '@example.com',
'Користувач ' || number
FROM generate_series(1, 10000) AS numbers(number);
CREATE INDEX users_email_hash_idx
ON users
USING hash (email);
ANALYZE users;
EXPLAIN
SELECT id, name
FROM users
WHERE email = 'user5000@example.com';У плані запиту може з’явитися Bitmap Index Scan або інший тип сканування, що використовує users_email_hash_idx.
На маленьких таблицях PostgreSQL часто вибирає послідовне сканування (Seq Scan), навіть якщо індекс існує. Це нормально: для невеликої кількості рядків прочитати всю таблицю може бути дешевше, ніж звертатися до індексу.
B-tree — стандартний тип індексу в PostgreSQL. Якщо тип індексу не вказати явно, PostgreSQL створить саме B-tree:
CREATE INDEX users_email_idx
ON users (email);Цей індекс еквівалентний:
CREATE INDEX users_email_idx
ON users USING btree (email);| Операція | Hash Index | B-tree | |---|---:|---:| | = | Так | Так | | >, <, >=, <= | Ні | Так | | Пошук діапазону | Ні | Так | | ORDER BY | Ні | Так | | Унікальний індекс | Ні | Так | | Точний пошук | Так | Так |
B-tree підтримує точне порівняння, тому для багатьох задач він є достатнім і більш універсальним рішенням.
Наприклад, B-tree може обслуговувати всі ці запити:
SELECT *
FROM users
WHERE email = 'user5000@example.com';
SELECT *
FROM users
WHERE id >= 100
AND id <= 200;
SELECT *
FROM users
ORDER BY email;Hash Index підходить лише для першого типу пошуку — точного порівняння.
Hash Index можна розглядати, якщо одночасно виконуються такі умови:
запити часто використовують =;
пошук за діапазоном не потрібен;
сортування за цим стовпцем через індекс не потрібне;
немає потреби створювати унікальний індекс;
після вимірювань Hash Index справді дає перевагу для конкретного навантаження.
Прикладом може бути пошук запису за довгим текстовим ідентифікатором, коли застосунок завжди порівнює його повністю:
SELECT *
FROM sessions
WHERE token = 'a-long-session-token';Однак сам факт використання точного порівняння ще не означає, що Hash Index буде кращим. B-tree також ефективно обробляє умову = і зазвичай є універсальнішим вибором.
Hash Index не можна оголосити унікальним. Такий запис некоректний:
CREATE UNIQUE INDEX users_email_hash_idx
ON users USING hash (email);Якщо потрібно гарантувати, що значення не повторюються, використовуйте унікальний B-tree:
CREATE UNIQUE INDEX users_email_unique_idx
ON users (email);Або обмеження таблиці:
ALTER TABLE users
ADD CONSTRAINT users_email_unique UNIQUE (email);Для видалення індексу використовують DROP INDEX:
DROP INDEX users_email_hash_idx;Якщо потрібно уникнути помилки, коли індексу вже немає:
DROP INDEX IF EXISTS users_email_hash_idx;Hash Index не призначений для таких умов:
WHERE price > 100;
WHERE created_at BETWEEN '2026-01-01' AND '2026-01-31';Для них зазвичай використовують B-tree:
CREATE INDEX products_price_idx
ON products (price);ORDER BYHash Index не зберігає ключі в порядку. Тому він не допоможе ефективно виконати:
SELECT *
FROM users
ORDER BY email;Для такого запиту підходить B-tree.
Hash Index не є автоматично швидшим за B-tree для кожного точного пошуку. На вибір плану впливають:
кількість рядків;
розподіл значень;
вибірковість умови;
кількість операцій читання і запису;
розмір таблиці;
статистика PostgreSQL.
Порівнювати індекси потрібно на даних, схожих на реальні, використовуючи EXPLAIN та EXPLAIN ANALYZE.
Кожен індекс займає місце та потребує оновлення під час INSERT, UPDATE і DELETE. Не варто створювати Hash Index лише тому, що умова використовує оператор =. Спочатку потрібно перевірити, чи наявний B-tree не задовольняє цю потребу.
Hash Index призначений насамперед для точного порівняння через =.
Він не підтримує ефективний пошук за діапазоном і сортування.
B-tree підтримує і точний пошук, і діапазони, і ORDER BY.
Hash Index не може бути унікальним.
Для більшості звичайних випадків B-tree є універсальним вибором за замовчуванням.
Hash Index варто використовувати лише після перевірки конкретного навантаження та планів запитів.