C.W.K.
Stream
Lesson 02 of 10 · published

쿼리 모양 먼저, 인덱스 두 번째

~12 min · operations, queries

Level 0스키마 새싹
0 XP0/86 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

쿼리가 lever

인덱스 추가 전에 물어: 쿼리가 DB 에게 너무 많이 시키나? 세 컬럼만 필요한데 SELECT *, 실제 안 쓰는 테이블 join, 순서 무관한데 LIMIT 전 ORDER BY — 다 인덱스가 못 고치는 쿼리-모양 문제.

고전적 모양 문제

  • 안 쓰는 컬럼 선택 (추가 IO, covering 인덱스 무력화).
  • 필터 또는 선택 안 하는 테이블 join.
  • 나중에 aggregate 가능한데 먼저 aggregate.
  • 캐시 가능한 비싼 표현식을 SELECT 리스트에서 계산.
  • '맞는 거 찾으려' 1만 행을 앱으로 가져오기 — DB 가 필터하게.

최적화 올바른 순서

  1. 쿼리 모양 수정 — 컬럼 좁히기, 행 좁히기, SQL 으로 작업 push.
  2. 그 다음 인덱스 추가 — EXPLAIN 이 여전히 문제 보이면.
  3. 그 다음 캐시 추가 — 데이터 자주 read + 거의 안 변할 때만.
  4. 그 다음 materialised view 추가 — aggregation 이 진짜 비쌀 때만.

Code

SELECT 슬림, JOIN 슬림·sql
-- 전: 세 테이블 모든 컬럼 가져오고 앱에서 필터
SELECT u.*, o.*, p.*
FROM   users u
LEFT JOIN orders o ON o.user_id = u.id
LEFT JOIN products p ON p.id = o.product_id;

-- 후: 필요한 컬럼과 행만
SELECT u.id, u.name, o.id AS order_id, o.total
FROM   users u
JOIN   orders o ON o.user_id = u.id
WHERE  o.placed_at >= now() - INTERVAL '30 days';
Aggregation 을 SQL 으로 push·sql
-- 전: 10만 행 가져와서 Python 에서 aggregate
rows = db.execute("SELECT total FROM orders WHERE customer_id = %s", (cid,)).fetchall()
total = sum(r[0] for r in rows)

-- 후: 한 쿼리가 한 숫자 반환
total = db.execute(
    "SELECT SUM(total) FROM orders WHERE customer_id = %s", (cid,)
).fetchone()[0]

External links

Exercise

프로젝트의 가장 느린 쿼리. 인덱스 만지기 전에 모양 감사: 반환되지만 안 쓰는 컬럼? 필터 안 된 join? 앱 코드에서 SQL 으로 옮길 수 있는 aggregation? 각 변경 후 재측정.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.