lesson ── postgres-labs ── ~22 мин ── 4 шагов
«Индекс есть, а не используется» - почти всегда про оператор, а не про
индекс. Возьмём JSONB-оператор @>, который btree игнорирует, и через
каталог определим, что нужен GIN. Запусти psql во вкладке client.
интерактивный sandbox
Поднимется контейнер postgreslab/postgres-base с PostgreSQL 17 и psql. В браузере откроется терминал, база lab уже настроена. Каждый шаг проверяется автоматически. Сеть air-gapped, наружу контейнер не ходит.
stack ── PostgreSQL 17 · psql · 1 GB RAM · air-gapped · самоуничтожается через 45 мин простоя
CREATE TABLE doc (id serial, body jsonb);
INSERT INTO doc(body)
SELECT jsonb_build_object('tag', CASE WHEN g%10=0 THEN 'sale' ELSE 'plain' END, 'n', g)FROM generate_series(1, 50000) g;
ANALYZE doc;
У JSONB-документа много ключей - btree по нему не поможет для содержания.
✓ Таблица doc с JSONB готова.
CREATE INDEX doc_btree ON doc (body);
EXPLAIN SELECT * FROM doc WHERE body @> '{"tag":"sale"}';btree на jsonb умеет сравнивать документы целиком, но не оператор
содержания @> - план остаётся Seq Scan.
Оператор @> не входит в operator class btree.
✓ Seq Scan - btree бесполезен для @>.
SELECT DISTINCT am.amname
FROM pg_amop aop
JOIN pg_operator op ON op.oid = aop.amopopr
JOIN pg_opfamily f ON f.oid = aop.amopfamily
JOIN pg_am am ON am.oid = f.opfmethod
WHERE op.oprname = '@>';
Предскажи ответ перед запуском: какие методы доступа поддержат @>?
Ожидается gin и gist - но не btree.
✓ Каталог подтвердил: @> поддерживает gin (и gist).
CREATE INDEX doc_gin ON doc USING gin (body);
ANALYZE doc;
EXPLAIN SELECT * FROM doc WHERE body @> '{"tag":"sale"}';Теперь @> в Index Cond, план идёт через GIN (Bitmap Index Scan).
GIN индексирует ключи и значения JSONB - оператор @> теперь sargable.
✓ GIN используется - правильный тип индекса выведен из каталога.
Индекс работает для операторов, а не «на колонке»; связь тип+оператор+AM задаёт operator class. Через pg_amop видно, какой метод доступа знает оператор: @> поддерживают gin и gist, но не btree. Поэтому JSONB-поиск по содержанию ускоряет GIN, а btree остаётся Seq Scan.
команды
SELECT amname FROM pg_am;методы доступаCREATE INDEX ON t USING gin (jsonb_col);GIN под оператор @>концепции