๐Ÿ’ฃย Problem


์„œ๋น„์Šค ๋‚ด์—์„œ ์œ ์ € ๋‹‰๋„ค์ž„์„ ํ‚ค์›Œ๋“œ๋กœ ์›ํ•˜๋Š” ์œ ์ €๋ฅผ ํƒ์ƒ‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. MySQL์„ ์กฐํšŒํ•˜๋Š” ์กฐ๊ฑด์ ˆ์— LIKE ์—ฐ์‚ฐ์ž๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

EXPLAIN SELECT * FROM users WHERE nickname LIKE '%nick%';

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2025-09-15 แ„‹แ…ฉแ„Œแ…ฅแ†ซ 12.26.48.png

EXPLAIN ํ‚ค์›Œ๋“œ๋ฅผ ํ†ตํ•ด ์‹คํ–‰ ๊ณ„ํš์„ ํ™•์ธํ–ˆ๊ณ , LIKE ์—ฐ์‚ฐ์—์„œ ์ ‘๋‘์–ด๊ฐ€ ์—†๋‹ค๋ฉด nickname ์ธ๋ฑ์Šค๋ฅผ ํ™œ์šฉํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ํ…Œ์ด๋ธ” ํ’€ ์Šค์บ”์ด ์ง„ํ–‰๋จ์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿชœย Solution


์ž‘ํ’ˆ ๊ฒ€์ƒ‰์ด ์•„๋‹Œ ๋‹‰๋„ค์ž„ ๊ธฐ๋ฐ˜์˜ ์œ ์ € ๊ฒ€์ƒ‰์€ ์ฃผ์š” ์„œ๋น„์Šค๋Š” ์•„๋‹ˆ์ง€๋งŒ, ์œ ์ €๊ฐ€ ๋งค์šฐ ๋งŽ์•„์กŒ์„ ๋•Œ๋ฅผ ์ธ๋ฑ์Šค๋ฅผ ํ™œ์šฉํ•˜์ง€ ๋ชปํ•˜๋Š” ์ฟผ๋ฆฌ๋Š” ์„ฑ๋Šฅ ์ด์Šˆ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ถ”๊ฐ€์ ์ธ ๋ฆฌ์†Œ์Šค ๋„์ž… ๋ถ€๋‹ด์—†์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธธ ์›ํ–ˆ๊ณ  MySQL์˜ Full Text Search์™€ ์ ‘๋‘์–ด ๊ธฐ๋ฐ˜ LIKE ์ฟผ๋ฆฌ, ํ˜„์ƒํƒœ ์œ ์ง€ ์ค‘์—์„œ ๊ฒฐ์ •ํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ„๋‹จํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

LIKE vs LIKE(์ ‘๋‘์–ด) vs FTS ํ…Œ์ŠคํŠธ

ALTER TABLE users ADD FULLTEXT(nickname) WITH PARSER ngram;

users ํ…Œ์ด๋ธ”์˜ nickname ์นผ๋Ÿผ ํ’€ ํ…์ŠคํŠธ ์ธ๋ฑ์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

SET cte_max_recursion_depth = 1000000; // CTE ์žฌ๊ท€ ๊นŠ์ด ์ˆ˜์ •

INSERT INTO users (email, password, nickname, provider, role, created_at)
WITH RECURSIVE seq AS (
    SELECT 0 AS n
    UNION ALL
    SELECT n + 1 FROM seq WHERE n < 999999
)
SELECT 
    CONCAT('user', n, '@example.com') AS email,
    'password123' AS password,
		CONCAT(SUBSTRING(MD5(RAND()), 1, 6), n) AS nickname,
    'LOCAL' AS provider,
    'USER' AS role,
    NOW() AS created_at
FROM seq;