ํ”ผ๋“œ๋กœ ๋Œ์•„๊ฐ€๊ธฐ
Stop Paying for Algolia: Master PostgreSQL Full-Text Search ๐Ÿ˜
Dev.toDev.to
Database

PostgreSQL FTS ๋„์ž…์œผ๋กœ ์™ธ๋ถ€ ๊ฒ€์ƒ‰ ์—”์ง„ ์—†์ด 1,000๋งŒ ๊ฑด ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ

Stop Paying for Algolia: Master PostgreSQL Full-Text Search ๐Ÿ˜

Prajapati Paresh2026๋…„ 5์›” 16์ผ3๋ถ„intermediate

Context

B2B SaaS ํ”Œ๋žซํผ์˜ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ ๊ตฌํ˜„์„ ์œ„ํ•ด Algolia, Elasticsearch ๋“ฑ ์™ธ๋ถ€ ์ „์šฉ ๊ฒ€์ƒ‰ ์—”์ง„ ๋„์ž…์„ ๊ฒ€ํ† ํ•จ. ์™ธ๋ถ€ ์„œ๋น„์Šค ์ด์šฉ ์‹œ ๋ฐœ์ƒํ•˜๋Š” ๋ฐ์ดํ„ฐ ๋™๊ธฐํ™” ๋ณต์žก์„ฑ, ์‹คํŒจ ํ ๊ด€๋ฆฌ ๋ถ€๋‹ด ๋ฐ ์›” ๊ตฌ๋… ๋น„์šฉ์ด๋ผ๋Š” ์•„ํ‚คํ…์ฒ˜์  ์˜ค๋ฒ„ํ—ค๋“œ ๋ฐœ์ƒ.

Technical Solution

  • Full Table Scan์„ ์œ ๋ฐœํ•˜๋Š” SQL LIKE ์—ฐ์‚ฐ์„ ๋Œ€์ฒดํ•˜๊ธฐ ์œ„ํ•ด PostgreSQL Full-Text Search(FTS) ์ฑ„ํƒ
  • ํ…์ŠคํŠธ๋ฅผ ์ •๊ทœํ™”๋œ ๋ฃจํŠธ ๋‹จ์–ด ๋ฆฌ์ŠคํŠธ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” tsvector ํƒ€์ž…์˜ Generated Column ์„ค๊ณ„
  • ๋ฐ์ดํ„ฐ ์‚ฝ์ž… ๋ฐ ์ˆ˜์ • ์‹œ ์ž๋™ ์—…๋ฐ์ดํŠธ๋ฅผ ๋ณด์žฅํ•˜๋Š” STORED ์†์„ฑ ์ ์šฉ์œผ๋กœ ๋™๊ธฐํ™” ๋กœ์ง ์ œ๊ฑฐ
  • ๊ฒ€์ƒ‰ ์†๋„ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด tsvector ์ปฌ๋Ÿผ์— GIN Index๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ฐ€๋ฆฌ์ดˆ ๋‹จ์œ„์˜ ์‘๋‹ต ์‹œ๊ฐ„ ํ™•๋ณด
  • title(A)๊ณผ content(B)์— ์„œ๋กœ ๋‹ค๋ฅธ ๊ฐ€์ค‘์น˜๋ฅผ ๋ถ€์—ฌํ•˜์—ฌ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ์˜ Relevance Rank ์ตœ์ ํ™”
  • websearch_to_tsquery ํ•จ์ˆ˜๋ฅผ ํ†ตํ•œ ๊ตฌ๊ธ€ ์Šคํƒ€์ผ์˜ ์ž์—ฐ์–ด ๊ฒ€์ƒ‰ ์ฟผ๋ฆฌ ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„

1. ๋ฐ์ดํ„ฐ ๊ทœ๋ชจ๊ฐ€ 1,000๋งŒ ๊ฑด ๋ฏธ๋งŒ์ธ ๊ฒฝ์šฐ ์™ธ๋ถ€ ๊ฒ€์ƒ‰ ์—”์ง„๋ณด๋‹ค DB ๋‚ด์žฅ FTS ์šฐ์„  ๊ฒ€ํ† 

2. GIN Index๋ฅผ ํ™œ์šฉํ•ด ๊ฒ€์ƒ‰ ์„ฑ๋Šฅ์„ ํ™•๋ณดํ•˜๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธ

3. Generated Column์„ ํ†ตํ•ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ณ„์ธต์˜ ๋™๊ธฐํ™” ์ฝ”๋“œ ์ œ๊ฑฐ ๊ฐ€๋Šฅ์„ฑ ๊ฒ€ํ† 

4. ts_rank ํ•จ์ˆ˜๋ฅผ ํ™œ์šฉํ•œ ๊ฐ€์ค‘์น˜ ๊ธฐ๋ฐ˜ ์ •๋ ฌ ์ ์šฉ ์—ฌ๋ถ€ ํ™•์ธ

์›๋ฌธ ์ฝ๊ธฐ