- แม้หลายคนจะมองว่า Full-Text Search (FTS) พื้นฐานของ PostgreSQL ช้า แต่ ถ้าปรับแต่งอย่างเหมาะสมก็ทำงานได้เร็วมาก
- บล็อกของ Neon เปรียบเทียบส่วนขยาย
pg_search ที่พัฒนาด้วย Rust กับ FTS พื้นฐาน และอ้างว่าแบบหลังช้ากว่า
- แต่การเปรียบเทียบนี้มีความเป็นไปได้สูงว่าเกิดขึ้นในสภาพที่ ขาดการปรับแต่งพื้นฐานที่จำเป็น สำหรับ PostgreSQL FTS
- บทความนี้พิสูจน์ด้วยตัวเลขว่า เพียงแค่ใช้การปรับแต่งง่าย ๆ กับการตั้งค่า FTS พื้นฐาน ก็เพิ่มประสิทธิภาพได้ถึง 50 เท่า
ภาพรวมการตั้งค่าเบนช์มาร์ก
- ทดสอบบนตารางที่มีข้อมูลล็อก 10 ล้านรายการ
CREATE TABLE benchmark_logs (
id SERIAL PRIMARY KEY,
message TEXT,
country VARCHAR(255),
severity INTEGER,
timestamp TIMESTAMP,
metadata JSONB
);
- โครงสร้างคิวรีที่เป็นปัญหา:
SELECT country, COUNT(*)
FROM benchmark_logs
WHERE to_tsvector('english', message) @@ to_tsquery('english', 'research')
GROUP BY country
ORDER BY country;
- รัน
to_tsvector() ภายในคิวรี → ไม่มีประสิทธิภาพอย่างมาก
- แม้จะมี GIN index ก็ใช้งานได้ไม่เต็มประสิทธิภาพ
สภาพแวดล้อมการทดสอบ (จำลองค่าตั้งต้นเดิม)
ปัจจัยที่ทำให้ประสิทธิภาพลดลง 1: การคำนวณ tsvector แบบเรียลไทม์
ปัจจัยที่ทำให้ประสิทธิภาพลดลง 2: การตั้งค่า fastupdate=on ของ GIN index
ตัวเลขประสิทธิภาพที่ดีขึ้น: มากกว่า 50 เท่า
- ก่อนปรับแต่ง: ประมาณ 41.3 วินาที (41,301 ms)
- หลังปรับแต่ง: ประมาณ 0.88 วินาที (877 ms)
- แสดงให้เห็นว่าประสิทธิภาพดีขึ้นราว 50 เท่า
- ทำได้แม้ในสภาพแวดล้อมที่มีจำนวน worker สำหรับการประมวลผลแบบขนานน้อยกว่า
ประสิทธิภาพของ ts_rank อาจช้าจริงในทางปฏิบัติ
ts_rank หรือ ts_rank_cd ต้องประเมินผลลัพธ์ทั้งหมดก่อนแล้วจึงจัดเรียง จึงอาจค่อนข้างช้า
- โดยเฉพาะเมื่อจัดการกับผลลัพธ์จำนวนมาก จะใช้ CPU/IO สูง
ฟีเจอร์จัดอันดับขั้นสูง: ส่วนขยาย VectorChord-BM25
- หากความแม่นยำและความเร็วของการจัดเรียงสำคัญมาก การใช้ส่วนขยายเฉพาะทางจะมีประสิทธิภาพกว่า
- VectorChord-BM25 เป็นส่วนขยายสำหรับ PostgreSQL ที่มีฟังก์ชันจัดอันดับบนอัลกอริทึม BM25
- มีรายงานว่าเร็วกว่า Elasticsearch ถึง 3 เท่า
ข้อดีของ VectorChord-BM25
- อัลกอริทึม BM25: อัลกอริทึมจัดอันดับการค้นหาที่พัฒนาต่อจาก TF-IDF
- รูปแบบดัชนีเฉพาะทาง: ปรับให้เหมาะกับการค้นหาความเร็วสูง เช่น Block WeakAnd
- มี type
bm25vector สำหรับเก็บ representation ที่ผ่านการ tokenize แล้ว
- เพิ่มทั้งความแม่นยำและความเร็วในการค้นหา
สรุป: FTS พื้นฐานของ PostgreSQL ก็เร็วได้มากพอ
- หากใช้คอลัมน์
tsvector และ GIN index ที่เหมาะสม (fastupdate=off) ก็สามารถค้นหาได้เร็วมากแม้ใช้ FTS พื้นฐาน
- การเปรียบเทียบด้านประสิทธิภาพควรทำบนพื้นฐานที่ผ่านการปรับแต่งแล้ว
- หากต้องการฟีเจอร์จัดอันดับขั้นสูง อาจพิจารณาใช้ส่วนขยายอย่าง VectorChord-BM25
- ข้อความสำคัญคือ ไม่ใช่เครื่องมือที่ช้า แต่อาจเป็นการตั้งค่าที่มีปัญหา
3 ความคิดเห็น
ขอบคุณ ทำให้ผมได้ปรับแต่งคิวรีครับ
ความเห็นใน Hacker News น่ากลัวจัง... "สิบล้านรายการ? ล้อเล่นหรือเปล่า?"
ความคิดเห็นจาก Hacker News
ในฐานะผู้ดูแล
pg_searchตามเอกสารของ Postgres ทั้งแนวทางในบทความของ Neon/ParadeDB และกลยุทธ์ที่ใช้ที่นี่ต่างก็ถูกเสนอเป็นทางเลือกที่ใช้ได้pg_searchถูกออกแบบมาเพื่อแก้ปัญหาอย่างหลัง และเบนช์มาร์กก็สะท้อนเรื่องนั้นpg_searchทำงานกับคิวรีแบบ "สไตล์ Elastic" ที่หลากหลายและชนิดข้อมูลของ Postgres ได้ด้วยการกำหนดดัชนีอย่างง่ายเท่านั้นการคำนวณ
tsvectorแบบเรียลไทม์เป็นความผิดพลาดครั้งใหญ่ไม่เข้าใจแนวโน้มที่พยายามยัดทุกอย่างลงใน Postgres
ดีใจที่ได้เห็นการทำ full-text search แบบ native ของ Postgres มากขึ้น
ไม่มี execution plan เลย ทำให้เข้าใจได้ยากว่าเกิดอะไรขึ้น
tsvectorแบบเรียลไทม์จะใช้เฉพาะกับรายการที่ตรงกันเท่านั้น และคิวรีเบนช์มาร์กมีLIMIT 10จึงมีการตรวจซ้ำไม่มากเมื่อหลายปีก่อนเคยอยากใช้ native FTS แต่ไม่สำเร็จ
ได้แพ็กเกจส่วนขยาย
pg_searchและvchord_bm25แบบ RPM/DEBเห็นหลายทีมข้ามไปใช้ Elasticsearch หรือ Meilisearch กันตรง ๆ
เรคอร์ด 10 ล้านรายการเป็นชุดข้อมูลระดับของเล่น
เริ่มใช้ pg full-text ครั้งแรกตั้งแต่ราวปี 2008