Skip to main content

[커넥트 지누] 인덱스를 활용해 학식 조회 성능을 개선해보기

•3 min•455 words

인덱스 조회

SELECT * FROM pg_indexes WHERE tablename = 'cafeteria_diet';

실행 결과

indexnameindexdef
cafeteria-diet_pkeyCREATE UNIQUE INDEX “cafeteria-diet_pkey” ON public.cafeteria_diet USING btree (diet_id)

인사이트

  • PostgreSQL은 MySQL과 다르게 FK 제약조건 생성 시 자동으로 인덱스를 만들어주지 않는다.

최적화 대상 쿼리

SELECT
    dish_category,
    dish_type,
    dish_name
FROM cafeteria_diet
WHERE cafeteria_id = 4
  AND date = '2025-05-13'
  AND time = '점심';

실행 결과

dish_categorydish_typedish_name
한식주식기장밥
한식국류해물보탕국
한식찬류치즈불닭

3. 실험 결과

3.1. 인덱스 없이 실행했을 때

EXPLAIN ANALYZE
SELECT
    dish_category,
    dish_type,
    dish_name
FROM cafeteria_diet
WHERE cafeteria_id = 4
  AND date = '2025-05-13'
  AND time = '점심';
QUERY PLAN
Seq Scan on cafeteria_diet (cost=0.00..1007.70 rows=3 width=39) (actual time=1.263..3.327 rows=9 loops=1)
Filter: ((cafeteria_id = 4) AND (date = ‘2025-05-13’::date) AND ((“time”)::text = ‘점심’::text))
Rows Removed by Filter: 32831
Planning Time: 0.068 ms
Execution Time: 3.350 ms

2. FK 단일 인덱스 적용

인덱스 생성

CREATE INDEX idx_cafeteria_diet_cafeteria_id
ON cafeteria_diet (cafeteria_id);

실행 결과

QUERY PLAN
Bitmap Heap Scan on cafeteria_diet (cost=20.86..494.14 rows=3 width=39) (actual time=0.260..0.425 rows=9 loops=1)
Recheck Cond: (cafeteria_id = 4)
Filter: ((date = ‘2025-05-13’::date) AND ((“time”)::text = ‘점심’::text))
Rows Removed by Filter: 2279
Heap Blocks: exact=84
-> Bitmap Index Scan on idx_cafeteria_diet_cafeteria_id (cost=0.00..20.86 rows=2302 width=0) (actual time=0.089..0.089 rows=2288 loops=1)
Index Cond: (cafeteria_id = 4)
Planning Time: 0.083 ms
Execution Time: 0.447 ms

3. 복합 인덱스 적용

인덱스 생성

CREATE INDEX idx_cafeteria_diet_date_cafeteria_time
ON cafeteria_diet (date, cafeteria_id, time);

실행 결과

QUERY PLAN
Index Scan using idx_cafeteria_diet_date_cafeteria_time on cafeteria_diet (cost=0.29..4.74 rows=5 width=39) (actual time=0.015..0.019 rows=9 loops=1)
Index Cond: ((date = ‘2025-05-13’::date) AND (cafeteria_id = 4) AND ((“time”)::text = ‘점심’::text))
Planning Time: 0.080 ms
Execution Time: 0.043 ms

4. 커버링 인덱스 적용

커버링 인덱스 추가

CREATE INDEX idx_cafeteria_diet_date_cafeteria_time_cover
ON cafeteria_diet (date, cafeteria_id, time)
INCLUDE (dish_category, dish_type, dish_name);

실행 결과

QUERY PLAN
Index Only Scan using idx_cafeteria_diet_date_cafeteria_time_cover on cafeteria_diet (cost=0.41..2.68 rows=3 width=39) (actual time=0.019..0.021 rows=9 loops=1)
Index Cond: ((date = ‘2025-05-13’::date) AND (cafeteria_id = 4) AND (“time” = ‘점심’::text))
Heap Fetches: 0
Planning Time: 0.083 ms
Execution Time: 0.041 ms

실험 결과 비교

인덱스 구성실행 계획실행 시간인덱스 크기
1️⃣ 인덱스 없음Seq Scan3.350 ms-
2️⃣ FK 단일 인덱스Bitmap Heap Scan0.447 ms240 kB
3️⃣ 복합 인덱스Index Scan0.043 ms432 kB
4️⃣ 커버링 인덱스Index Only Scan0.041 ms2656 kB

결론

  • 실험 결과, 본 쿼리 패턴에서는 복합 인덱스가 성능과 저장 공간 측면에서 가장 합리적인 선택임을 확인하였다.