lesson ── postgres-labs ── ~22 мин ── 4 шагов
GiST понимает «пересекается», чего B-tree не умеет. Построим запрет
двойного бронирования через exclusion constraint и увидим, как GiST
ускоряет поиск по пересечению диапазонов. Запусти psql во вкладке
client.
интерактивный sandbox
Поднимется контейнер postgreslab/postgres-base с PostgreSQL 17 и psql. В браузере откроется терминал, база lab уже настроена. Каждый шаг проверяется автоматически. Сеть air-gapped, наружу контейнер не ходит.
stack ── PostgreSQL 17 · psql · 1 GB RAM · air-gapped · самоуничтожается через 45 мин простоя
CREATE TABLE room_booking (
room int,
during tstzrange,
EXCLUDE USING gist (room WITH =, during WITH &&)
);
Читается: не должно быть двух строк с одинаковой комнатой и пересекающимися интервалами.
EXCLUDE USING gist опирается на GiST, потому что нужен оператор &&.
✓ Exclusion constraint создан.
INSERT INTO room_booking VALUES
(1, '[2026-01-01 10:00, 2026-01-01 12:00)'),
(1, '[2026-01-01 12:00, 2026-01-01 14:00)');
-- эта пересекается с первой - предскажи результат:
INSERT INTO room_booking VALUES
(1, '[2026-01-01 11:00, 2026-01-01 13:00)');
Вторая вставка падает с conflicting key (exclusion). В таблице остаются только две непересекающиеся брони.
Интервалы [10:00,12:00) и [11:00,13:00) пересекаются - GiST это ловит.
✓ Пересекающаяся бронь отклонена - в таблице ровно две строки.
CREATE TABLE cal AS
SELECT g id, tstzrange(now() + (g || ' hours')::interval,
now() + ((g+1) || ' hours')::interval) during
FROM generate_series(1, 50000) g;
CREATE INDEX cal_gist ON cal USING gist (during);
ANALYZE cal;
GiST хранит охватывающий интервал поддерева - спуск идёт по пересечению.
✓ GiST-индекс по диапазону готов.
EXPLAIN SELECT * FROM cal
WHERE during && tstzrange(now() + interval '100 hours', now() + interval '101 hours');
Узкий интервал пересекает мало строк - GiST отсекает остальные ветви, план идёт по индексу (с Recheck Cond, GiST неточен).
Оператор && поддерживает только GiST, не B-tree.
✓ GiST ускорил поиск по пересечению диапазонов.
GiST - дерево для пересечений, содержания и расстояний (&&, @>, <->), чего B-tree не умеет. Exclusion constraint (EXCLUDE USING gist) декларативно запрещает пересечения - например, двойное бронирование. GiST обычно lossy: после индексного отбора идёт Recheck Cond.
команды
EXCLUDE USING gist (a WITH =, r WITH &&)запрет пересечений диапазоновCREATE INDEX ON t USING gist (range_col);GiST для поиска по && и @>концепции