PlanetScale TIN: full-text search Postgres nhanh gấp 25 lần

Một benchmark công bố hôm 16/9 cho thấy chênh lệch hiệu năng full-text search trên Postgres lớn tới mức khó tin: 25 lần throughput, 26 lần latency. Không phải quảng cáo — có bảng số liệu, có corpus 85GB, có đối thủ cụ thể.
Chuyện gì vừa xảy ra
PlanetScale — nhà cung cấp managed Postgres/MySQL cloud — vừa ra mắt TIN (Text INdex), một extension full-text search cho Postgres, hiện đã GA trên toàn bộ database PlanetScale và Neki. Cú pháp dùng đơn giản như một loại index thường:
CREATE INDEX an_index_name ON table_name USING tin(text_column_name);
SELECT * FROM table_name
WHERE text_column_name ==> 'some words';
Postgres vốn có GIN built-in cho full-text search, và cộng đồng đã có ParadeDB, pg_textsearch làm extension bổ sung. PlanetScale khẳng định TIN nhanh hơn cả ba, và họ đưa ra số liệu để chứng minh thay vì chỉ nói suông.
Benchmark: chênh lệch không phải kiểu vài phần trăm
PlanetScale test trên AWS i7i.8xlarge, giới hạn container 8 vCPU/32GB RAM, dùng corpus 85GB gồm 150 triệu câu hỏi-trả lời từ Stack Exchange. Họ so TIN v1.0.2 với ParadeDB v0.25.2, pg_textsearch v1.4.0 và Postgres GIN builtin (Postgres 18.6).
Kết quả build index đã lệch rõ:
| Engine | Thời gian build | Kích thước index | RAM cần |
|---|---|---|---|
| TIN | 8m10s | 50.7 GB | 32 GB |
| ParadeDB | 19m20s | 52.1 GB | 64 GB |
| pg_textsearch | 26m49s | 41.5 GB | 128 GB |
| Postgres GIN | 2h09m04s | 28.0 GB | 64 GB |
Ở phần truy vấn — nơi thật sự quan trọng với production — khoảng cách còn lớn hơn. Với mixed query (kết hợp conjunction, disjunction, phrase) trả top-10 theo điểm BM25, TIN đạt 199 QPS với p99 256ms; ParadeDB chỉ 7,9 QPS với p99 6.765ms. Tức TIN xử lý gấp 25 lần số query mỗi giây, và khi có query chậm nhất thì vẫn nhanh hơn 26 lần. Postgres GIN không hoàn thành nổi benchmark này vì hết RAM khi chạy disjunction search.
Với riêng conjunction và phrase query, TIN nhanh gấp 10 lần ParadeDB và 541 lần GIN. Ngay cả khi có client khác đang ghi 1.000 UPDATE/giây song song, TIN vẫn hoàn thành 270.279 lượt update trong 10 phút test, so với 185.584 của ParadeDB và vỏn vẹn 735 của pg_textsearch — vì pg_textsearch giữ lock đọc liên tục khiến write gần như đứng hình.
Vì sao nhanh vậy — mẹo nằm ở chỗ không cần "dịch" ID
Đây là phần thú vị nhất, không chỉ là con số. Các text index thông thường (kể cả ParadeDB, pg_textsearch) đánh số document tuần tự trong mỗi segment để nén postings list hiệu quả. Nhưng Postgres nội bộ không dùng ID tuần tự — nó dùng ctid, một con số 48-bit định vị chính xác vị trí vật lý của dòng dữ liệu trên heap.
Kết quả: mỗi lần trả về 10 triệu document khớp, ParadeDB và pg_textsearch phải tra ngược 10 triệu ID tuần tự đó về ctid thật thông qua một bảng mapping riêng. TIN bỏ qua bước này hoàn toàn — nó dùng thẳng ctid làm document identifier từ đầu. Không mapping, không tra ngược, không tầng trung gian.
Cái giá phải trả là bài toán nén khó hơn: ctid là số 48-bit rời rạc, không liên tục như ID tuần tự, nên các kỹ thuật nén cổ điển như delta-encoding không ăn được. PlanetScale giải bằng bitmap hai tầng, tận dụng đặc tính mỗi page Postgres chứa tối đa 291 tuple — đủ ít để bitmap theo page vẫn nén tốt. Với term tần suất cao, họ đạt xấp xỉ 1 bit mỗi posting.
So what — ảnh hưởng gì tới developer?
Nếu team đang build search feature (e-commerce, log search, tìm tài liệu nội bộ) trên Postgres và từng cân nhắc "thôi bắn thẳng sang Elasticsearch/Meilisearch cho nhanh" — số liệu này đáng để xem lại. Chênh lệch 10-25 lần QPS đủ lớn để đổi cách trả lời câu hỏi "có cần thêm một hệ thống search riêng không?" Giữ mọi thứ trong Postgres nghĩa là bớt một service phải vận hành, bớt một tầng đồng bộ dữ liệu, bớt một điểm lỗi.
Nhưng cần tỉnh táo với hai điều. Một, đây là benchmark do chính PlanetScale công bố, không phải bên thứ ba độc lập — dù họ có công khai corpus, câu lệnh test và mã nguồn benchmarker đã fork, vẫn nên tự chạy lại trên workload thật của mình trước khi đổi. Hai, TIN hiện GA trên hạ tầng PlanetScale — không rõ có bản standalone cho Postgres tự host hay không tại thời điểm bài viết, nên team không dùng PlanetScale cần kiểm tra kỹ trước khi kỳ vọng dùng được ngay.
Với những ai đã ở trên PlanetScale, đây là lý do đủ mạnh để thử CREATE INDEX ... USING tin(...) trên một bảng thật, đo lại bằng workload của chính mình thay vì tin số liệu marketing.
Điều cần biết
- TIN (Text INdex) — extension full-text search mới của PlanetScale, GA cho mọi database PlanetScale/Neki, ra mắt 16/9/2026
- Benchmark trên corpus Stack Exchange 85GB: nhanh hơn ParadeDB 10-25 lần QPS, hơn Postgres GIN builtin tới 541 lần với một số loại query
- Bí quyết kỹ thuật: dùng thẳng
ctidnội bộ của Postgres làm document ID, bỏ qua tầng mapping ID tuần tự mà các engine khác cần - Vẫn giữ throughput tốt khi có 1.000 UPDATE/giây chạy song song — điểm yếu truyền thống của text index
- Benchmark do PlanetScale tự công bố; chưa rõ khả năng dùng ngoài hạ tầng PlanetScale tại thời điểm bài viết
Bài viết được hỗ trợ bởi AI (Amy 🌸). Nội dung đã được kiểm duyệt bởi tác giả.
Related Posts
AWS mua DuckLabs: DuckDB về tay Amazon, mã nguồn mở đi về đâu?
Amazon ký thỏa thuận mua DuckLabs, công ty đứng sau DuckDB. Mã MIT và quỹ DuckDB Foundation vẫn giữ — nhưng liệu DuckDB còn trung lập?
Rust Glancer: LSP Rust mới chỉ dùng dưới 100MB RAM
rust-analyzer ngốn hàng GB RAM vì kiến trúc incremental. Rust Glancer đi ngược lại: index một lần, lưu ra ổ đĩa, idle dưới 100MB.
DuckDB 2.0 preview: từ thư viện nhúng thành server thực thụ
Bản preview DuckDB 2.0 lần đầu biến DuckDB thành server, kèm kiểu VARIANT, trigger và truy vấn đệ quy nhanh gấp 40 lần.