PlanetScale представила TIN (Text INdex) — расширение PostgreSQL для полнотекстового поиска с ранжированием BM25 и цифрами производительности, которые выглядят неприлично хорошо на фоне привычного GIN.

Инженерная часть там действительно интересная. Но прежде чем загораться, стоит выяснить один вопрос, который в анонсе не выделен, — и ответ на него для большинства читателей решает всё.

Факты — из анонса PlanetScale (Eric Ridge, Patrick Reynolds, 16 сентября 2026), документации и репозиториев. Разбор и проверка доступности мои.

Какую задачу решает

Полнотекстовый поиск в PostgreSQL существует давно — tsvector плюс индекс GIN. Проблема не в том, что его нет, а в том, что он плохо тянет сочетание требований, возникающее в реальном приложении:

Последний пункт — причина, по которой поиск часто выносят в Elasticsearch, а потом годами живут с рассинхронизацией двух хранилищ. TIN пытается закрыть задачу внутри базы.

Синтаксис минималистичный:

SQL
CREATE INDEX an_index_name ON table_name USING tin(text_column_name);

SELECT * FROM table_name WHERE text_column_name ==> 'some words';

SELECT * FROM products WHERE description ==> 'stretch denim jeans'
  ORDER BY tin.score(ctid) DESC LIMIT 10;
Нажмите, чтобы развернуть и увидеть больше

Инженерная идея

Здесь самое любопытное, и это стоит разобрать независимо от того, будете вы этим пользоваться или нет.

Идентификатор документа — это ctid. Обычные поисковые индексы ведут собственную нумерацию документов и отдельную структуру, отображающую её на строки таблицы. TIN использует штатный ctid PostgreSQL — 48-битный физический адрес кортежа. Отдельного отображения не нужно вовсе: индекс сразу знает, где лежит строка.

Побочный эффект приятный: результаты естественным образом выходят в порядке страниц кучи, то есть чтение идёт последовательно, а не случайными скачками по диску.

Двухуровневые битовые карты. Данные разложены на карты уровня страницы (256 бит — ровно регистр AVX2) и уровня смещения внутри страницы. Пересечения и объединения множеств документов считаются векторными инструкциями процессора, а не поэлементно.

Видимость через ту же механику. Проверка видимости транзакций — это пересечение постраничной битовой карты с картой видимости PostgreSQL. То есть корректность MVCC не прикручена сбоку, а встроена в ту же операцию, что и поиск.

Сегменты и фоновая работа. Данные лежат в изменяемых и неизменяемых сегментах; фоновые процессы переводят первые во вторые и сливают сегменты между собой. У каждого сегмента своя карта живых записей — через неё дружит с VACUUM. Логика узнаваемая: тот же принцип «пиши в мутабельный буфер, сливай в иммутабельные куски», что и у LSM-подобных движков вроде MergeTree в ClickHouse.

Цифры

Бенчмарк на корпусе Stack Exchange: 85 ГБ, 150 миллионов документов.

СценарийTINParadeDBGIN
Смешанные запросы, топ-10199 QPS, p99 256 мс7.9 QPSOOM
Конъюнкции и фразы, топ-10242 QPS24 QPS0.4 QPS
Дизъюнкции с обновлениями125 QPS2.2 QPSOOM
COUNT по дизъюнкции (Wikipedia)10 260 QPS, p99 2 мс291 QPS1.4 QPS

Сборка индекса — 8 минут 10 секунд, размер 50.7 ГБ при 32 ГБ оперативной памяти.

Разрыв заявлен от 8 до 541 раз. Оговорка обязательная: это бенчмарки вендора на его же сценариях. Строки с OOM у GIN показательны сами по себе, но проверять такое нужно на своих данных и своих запросах.

Большая оговорка

А теперь то, ради чего стоило проверять источники.

TIN нельзя поставить себе. Это не расширение, которое вы соберёте и загрузите в свой PostgreSQL. Оно доступно только на управляемых базах PlanetScale — как функция сервиса, а не как open source.

Открыт другой проект — lead (AGPL-3.0, Rust). И вот как его описывают сами авторы: это намеренно непродакшновое расширение, чтобы гонять TIN-совместимый SQL в разработке, CI и staging. Оно ставит корректность и компактность выше производительности и сознательно непригодно для продовых нагрузок.

То есть картина такая:

Где работаетЛицензияДля прода
TINтолько PlanetScaleзакрытда
leadгде угодноAGPL-3.0нет, явным текстом

Логика вендора понятна и по-своему честная: lead позволяет разработчику писать и тестировать те же запросы локально, не имея доступа к проду. Но если вы держите PostgreSQL сами — а это большинство читателей такого блога, — вам эти цифры недоступны.

Что делать, если хостите сами

Три варианта, которые реально можно поставить:

И старое доброе решение: вынести поиск наружу, в OpenSearch или аналог, приняв цену синхронизации. Именно от неё TIN и пытается избавить — но только своим клиентам.

Итог

Техническая часть сильная, и идея с ctid вместо собственной нумерации документов красива: индекс перестаёт быть параллельной вселенной со своим учётом строк и начинает говорить с базой на её же языке — физических адресов и карт видимости. Это стоит знать, даже если пользоваться не придётся.

Практический же вывод короткий: это функция управляемого сервиса, а не расширение PostgreSQL. Заголовок «полнотекстовый поиск для Postgres» читается как что-то, что можно поставить себе, — и в этом главная неточность восприятия. Если вы на PlanetScale, попробуйте. Если нет — смотрите pg_textsearch и не ждите тех же цифр.

Авторские права

Автор: Vasiliy Koshkin

Ссылка: https://notes.melancholic.tech/posts/planetscale-tin-postgres-search/

Лицензия: CC BY-NC-SA 4.0

Использование материалов блога разрешается при условии: указания авторства/источника, некоммерческого использования и сохранения лицензии.

Начать поиск

Введите ключевые слова для поиска статей

↑↓
↵
ESC
⌘K Горячая клавиша