
๐ฆ 4ํธ. DB ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง ์ง์ค ๋ถ์ + ์ค์ ๋ก ํจ๊ณผ๊ฐ ์ปธ๋ SQL ํ๋ ์ฌ๋ก
๋ฐฑ์๋ ์๋น์ค๊ฐ ์ปค์ง์๋ก ๋ณ๋ชฉ์ ๋๋ถ๋ถ์ ๊ฒฐ๊ตญ DB์์ ๋ฐ์ํ๋ค.
Spring, JVM, ๋คํธ์ํฌ ํ๋๋ ์ค์ํ์ง๋ง, ์ด์ ๊ฒฝํ์ ๊ฐ์ฅ ์ฆ๊ฐ์ ์ด๊ณ ๊ฐ์ฅ ํฐ ์ฑ๋ฅ ๊ฐ์ ํจ๊ณผ๋ฅผ ์ฃผ๋ ์ง์ ์ ๋ฐ๋ก DB ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง → SQL ํ๋์ด๋ค.
์ด๋ฒ ํธ์์๋ ์ค์ ์ด์ ํ๊ฒฝ์์ ์ฌ์ฉํ๋ DB ๋ชจ๋ํฐ๋ง ๋ฐฉ์๊ณผ
์ฑ๋ฅ์ ๋ช ๋ฐฐ๊น์ง ๋์ด์ฌ๋ฆฐ ์ค์ SQL ํ๋ ์ฌ๋ก๋ฅผ ์ ๋ฆฌํ๋ค.
โ 1) DB ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง์ ํต์ฌ ๊ด์
DB ์ฑ๋ฅ์ ์๋ 4๊ฐ์ง ์งํ๋ฅผ ์ค์ฌ์ผ๋ก ์ถ์ ํ๋ฉด ๋๋ถ๋ถ ๋ฌธ์ ๋ฅผ ์ฐพ์ ์ ์๋ค.
โ 1) ๋๋ฆฐ ์ฟผ๋ฆฌ(Slow Query) ๋ชจ๋ํฐ๋ง
์ค์ ์ด์์์ ๊ฐ์ฅ ์ค์ํ ์งํ
- ํ๊ท ์ฟผ๋ฆฌ ์๋ต์๊ฐ
- 95/99 percentile
- ์ด๋น ์ฟผ๋ฆฌ ๊ฑด์(QPS)
MySQL ์:
- slow query log ํ์ฑํ
- pt-query-digest๋ก ํจํด ๋ถ์
- AWS RDS → Performance Insights
Oracle/Sybase ์:
- AWR / ASH / Statspack
- sp_showplan / monitoring view
- BI Matrix ํน์ ์ ์ฌ SQL ๋ชจ๋ํฐ๋ง ๋๊ตฌ
โ 2) ๋ฝ(Lock) & ๋ฝ ๊ฒฝํฉ(Lock Contention)
DB ๊ณ ์ง์ ๋ณ๋ชฉ 1์์.
์์ฃผ ๋ณด๋ ์งํ:
- row lock, table lock
- lock wait time
- deadlock ๋ฐ์ ์ฌ๋ถ
- ํน์ ํธ๋์ญ์ ์ ๋๊ธฐ์ด ๊ธธ์ด
ํนํ ๊ธ์ต๊ถ์์๋ ๋ฝ ํ๋ ๋๋ฌธ์ ์ ์ฒด ๋ฐฐ์น๊ฐ ๋ช ์๊ฐ ์ง์ฐ๋๊ธฐ๋ ํ๋ค.
โ 3) ์ธ๋ฑ์ค ์ฌ์ฉ ์ฌ๋ถ & ํ์ค์บ ํ์ง
์ธ๋ฑ์ค๊ฐ ์์ด๋ ์กฐ๊ฑด์ด ์๋ ์ค ํ๋๋ฉด ์ธ๋ฑ์ค๋ฅผ ๋ฌด์ฉ์ง๋ฌผ๋ก ๋ง๋ ๋ค.
- LIKE ‘%keyword’
- ๊ณ์ฐ์ ํฌํจ: WHERE DATE(created_at) = ...
- ๋ฒ์ ์กฐ๊ฑด ๋จ๋ฐ
- OR ์กฐ๊ฑด ๋ค์
- ์ธ๋ฑ์ค ์ปฌ๋ผ ๋ถ์ผ์น(์คํค๋ง-์ฟผ๋ฆฌ mismatch)
์ค์ ์ด์์์๋ ์คํ๊ณํ(EXPLAIN) ์ ๋ณํ๋ง ๋ด๋ ๋๋ถ๋ถ ๋ฌธ์ ๋ฅผ ์ฐพ๋๋ค.
โ 4) ์ธ์ /์ปค๋ฅ์ ๋ชจ๋ํฐ๋ง
- connection pool ์ฌ์ด์ฆ ๋ถ์กฑ
- idle session ๋์
- max_connections ์ด๊ณผ
- ์ฅ์๊ฐ ์คํ๋๋ ์ค๋๋ ์ธ์ (=์ข๋น ์ธ์ )
Spring Boot์์ HikariCP ๋ก๊ทธ๋ง ๋ด๋ ์๋น ๋ถ๋ถ ํ์ ํ ์ ์๋ค.
โ 2) ์ค์ ํ๊ฒฝ์์ ์ฌ์ฉํ๋ ๋ชจ๋ํฐ๋ง ๋๊ตฌ
๐ฆ Spring ๊ธฐ๋ฐ ์๋น์ค ๋ด๋ถ ๋ชจ๋ํฐ๋ง
- Actuator + Micrometer
- Prometheus + Grafana (์ฟผ๋ฆฌ ์ง์ฐ/connection pool ์งํ ์๊ฐํ)
- P6Spy, datasource proxy
๐ง DB ์์ฒด ๋ชจ๋ํฐ๋ง
- MySQL Performance Schema
- Oracle AWR/ASH
- Sybase monitor view
- PostgreSQL pg_stat_statements
๐ฉ ๋ก๊ทธ/์์คํ ๋ ๋ฒจ
- CloudWatch / RDS Insights
- ELK Stack
- pin-point, ์ค์นด์ฐํฐ
์ด์์ด ์์ ๋ ํ์ผ์๋ก ์ ๋๊ตฌ๋ค์ ๋์์ ํ์ฉํ๋ค.
โ 3) ์ค์ ์์ ‘ํจ๊ณผ๊ฐ ์์ฒญ ์ปธ๋’ SQL ํ๋ ์ฌ๋ก
์ด์ ํ๊ฒฝ์์ ์ค์ ๋ก ์ฑ๋ฅ์ด ํฌ๊ฒ ๊ฐ์ ๋์๋ ๋ํ ์ฌ๋ก๋ค๋ง ์ ๋ฆฌํ๋ค.
๐ฆ ์ฌ๋ก 1) OR → UNION ALL๋ก ๋ณํ (2000ms → 80ms)
๋ฌธ์ ์ฟผ๋ฆฌ:
SELECT * FROM orders
WHERE status = 'PAID'
OR status = 'READY'
OR status = 'COMPLETE';
๋ฌธ์ ์ :
- OR ์กฐ๊ฑด์ด ๋ง์์ง๋ฉด ์ธ๋ฑ์ค๋ฅผ ๋ชป ํ๊ฑฐ๋ index merge๊ฐ ๋ฐ์
- leading column ํ๋๊ฐ ์ฑ๋ฅ์ ์ข์ฐํ๋๋ฐ OR๊ฐ ์ด๋ฅผ ํ๊ดด
๊ฐ์ ์:
SELECT * FROM orders WHERE status = 'PAID'
UNION ALL
SELECT * FROM orders WHERE status = 'READY'
UNION ALL
SELECT * FROM orders WHERE status = 'COMPLETE';
๊ฒฐ๊ณผ:
- ์ธ๋ฑ์ค๋ฅผ ์ธ ๋ฒ ์ ํ๋ ๊ฒ์ผ๋ก ๋ถํ
- ์๋ต์๊ฐ 2000ms → 80ms (์ฝ 25๋ฐฐ ๊ฐ์ )
๐ฆ ์ฌ๋ก 2) COUNT(*) ๋๋ ์ง๊ณ → ์นด์ดํธ ์ ์ฉ ํ ์ด๋ธ๋ก ๋ณ๊ฒฝ (๋ฐฐ์น 3์๊ฐ → 20๋ถ)
๋ฌธ์ :
SELECT COUNT(*) FROM transaction_log WHERE created_at BETWEEN ? AND ?;
transaction_log๊ฐ ์์ฒ๋ง ๊ฑด ์ด์์ผ๋ก ์ฆ๊ฐํ๋ฉด์ ์ง๊ณ ๋ฐฐ์น๊ฐ ํญ๋ฐ.
๊ฐ์ :
- ๋งค์ผ 0์๋ง๋ค summary table์ count๋ง ์ ์ฅ
- ์ด์ ์ฟผ๋ฆฌ๋ summary table์ ์กฐํ
๊ฒฐ๊ณผ:
- ๋ฐฐ์น 3์๊ฐ → 20๋ถ
- ์ ํ๋ฆฌ์ผ์ด์ ์์ CPU ์ฌ์ฉ๋ 70% ๊ฐ์
๐ฆ ์ฌ๋ก 3) JOIN 4๋จ๊ณ → ์๋ธ์ฟผ๋ฆฌ ์บ์ฑ + ์ธ๋ฑ์ค ์ ๋ ฌ (800ms → 40ms)
๋ฌธ์ :
- A → B → C → D ์กฐ์ธ์ ํตํด ๋จ์ผ ์ํ ์ ๋ณด๋ฅผ ์กฐํ
- C ํ ์ด๋ธ์์ full scan ๋ฐ์
์์ธ:
- C ํ ์ด๋ธ์ join key ์ปฌ๋ผ์ ์ธ๋ฑ์ค ์์์
- order by ๋๋ฌธ์ filesort ๋ฐ์
๊ฐ์ :
- ํ์ํ join key์ composite index ์์ฑ
- ์ ๋ ฌ ์กฐ๊ฑด์ ์ธ๋ฑ์ค ์์์ ์ผ์นํ๋๋ก ๋ณ๊ฒฝ
- ์ผ๋ถ ์๋ธ์ฟผ๋ฆฌ๋ Redis ์บ์ฑ
๊ฒฐ๊ณผ:
- 800ms → 40ms (20๋ฐฐ ๋จ์ถ)
๐ฆ ์ฌ๋ก 4) LIKE ‘%keyword’ → ์ญ์ธ๋ฑ์ค + ๊ฒ์ ์ ์ฉ ํ ์ด๋ธ (1500ms → 50ms)
๋ฌธ์ :
WHERE name LIKE '%์ํ%'
๊ฐ์ :
- ์ญ์ธ๋ฑ์ค or N-gram ์ธ๋ฑ์ค ์ ์ฉ
- ๊ฒ์ ์ ์ฉ ํ ์ด๋ธ ์์ฑ
- ๋๋ ElasticSearch๋ก ๋ถ๋ฆฌ
๊ฒฐ๊ณผ:
- 1500ms → 50ms
- ๊ฒ์ API 30๋ฐฐ ํฅ์
๐ฆ ์ฌ๋ก 5) ๋ฌด๊ฑฐ์ด ์ ๋ ฌ ์ ๊ฑฐ (order by → limit ์ต์ ํ) 1200ms → 60ms
๊ธฐ์กด:
SELECT * FROM account_history
WHERE user_id = ?
ORDER BY created_at DESC
LIMIT 20;
๋ฌธ์ :
- created_at ์ธ๋ฑ์ค๊ฐ ์์ด ์ ์ฒด ์ ๋ ฌ ๋ฐ์
๊ฐ์ :
CREATE INDEX idx_history_user_created_at ON account_history(user_id, created_at DESC);
๊ฒฐ๊ณผ:
- ์ ๋ ฌ ๋น์ฉ ์ ๊ฑฐ
- 1200ms → 60ms
โ 4) Spring์์ SQL ํ๋ ํจ๊ณผ๋ฅผ ์ต๋ํํ๋ ๋ฐฉ์
โ 1) ๋ถํ์ํ Lazy ๋ก๋ฉ ์ฐจ๋จ
@Query("select u from User u join fetch u.orders where u.id = :id")
โ 2) DTO projection ์ ๊ทน ์ฌ์ฉ
์ํฐํฐ ๊ธฐ๋ฐ๋ณด๋ค ์ ์ก ๋น์ฉ 30~80% ์ ๊ฐ.
โ 3) ๋๋ insert/update๋ batch ์ต์ ํ์
HikariCP + Hibernate batch ์ต์ ์กฐํฉ ํจ๊ณผ ํผ.
โ 4) ์ฝ๊ธฐ ์ ์ฉ ์ฟผ๋ฆฌ๋ replica๋ก ๋ถ๋ฆฌ
์ฝ๊ธฐ ๋ถํ๊ฐ ๋ง์ ์๋น์ค์์๋ ๋ฌด์กฐ๊ฑด ํด์ผ ํ๋ ๊ตฌ์กฐ.
โ 5) ๋ง๋ฌด๋ฆฌ
์ด๋ฒ ํธ์์๋ ์ค์ ํ๊ฒฝ์์ ๋ฐ๋ก ์ฐ๋ DB ๋ชจ๋ํฐ๋ง ์งํ์ ๋๊ตฌ,
๊ทธ๋ฆฌ๊ณ ์ค์ ์ด์์์ ํจ๊ณผ๊ฐ ์ปธ๋ SQL ํ๋ ์ฌ๋ก๋ค์ ์๊ฐํ๋ค.
ํต์ฌ์ ํ๋๋ค.
DB๋ “๊ฐ”์ด ์๋๋ผ “์งํ + ์คํ๊ณํ + ํจํด ๋ถ์”์ผ๋ก ํ๋ํด์ผ ํ๋ค.
๋ค์ ํธ์์๋ ๋๋์ด:
“์ค์ ์ด์ ์ฅ์ ์ฌ๋ก 10์ + ์ฅ์ ๋ณต๊ตฌ ํ๋ ์ด๋ถ”
์ ๋ค๋ค ๋๋ฆด๊ฒ์.
- 1ํธ — ์ด์ ์๋ฒ์์ ์ค์ ๋ก ํจ๊ณผ ๋ณธ ๋ฐฉ๋ฒ
- 2ํธ — Jackson ์ง๋ ฌํ ํ๋: ์จ์ CPU ๋ณ๋ชฉ ํด๊ฒฐ
- 3ํธ — ThreadPool & Tomcat ํ๋: ํธ๋ํฝ ํญ์ฃผ ๋์
- 4ํธ — DB ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง๊ณผ SQL ํ๋ ์ฌ๋ก (ํ์ฌ ๊ธ)
- 5ํธ — ์ด์ ์ฅ์ ์ฌ๋ก 10์ + ์ฅ์ ๋ณต๊ตฌ ํ๋ ์ด๋ถ