데이터베이스의 성능에는 테이블, 쿼리, 설정 등 다양한 수준의 요소들이 영향을 미친다. 최적화 방법을 살펴보기 전에 아래 질문으로 어떤 점을 고려해야 하는지 간단히 알아보자.
데이터베이스에서 인덱스는 테이블에 대한 검색 속도를 높여주는 자료 구조를 의미한다. 특정 컬럼에 인덱스를 생성하면 전체 테이블을 풀 스캔하는 대신 인덱스를 참조하여 원하는 결과를 빠르게 조회할 수 있다.
tarot_card
테이블에는 id
와 card_pack_id
가 키로 설정되어 있다. SHOW INDEX FROM...
명령으로 인덱스 정보를 조회하면, 앞서 언급한 키들이 자동으로 인덱스로 등록된 것을 확인할 수 있다.
SELECT `TarotCard`.`id` AS `TarotCard_id`, `TarotCard`.`card_no` AS `TarotCard_card_no`, `TarotCard`.`ext` AS `TarotCard_ext`, `TarotCard`.`created_at` AS `TarotCard_created_at`, `TarotCard`.`updated_at` AS `TarotCard_updated_at`, `TarotCard`.`deleted_at` AS `TarotCard_deleted_at`, `TarotCard`.`card_pack_id` AS `TarotCard_card_pack_id`
FROM `tarot_card` `TarotCard`
WHERE ( (`TarotCard`.`card_no` = ?) ) AND ( `TarotCard`.`deleted_at` IS NULL ) LIMIT 1
위 sql문은 typeorm의 로그에 기록된, 타로 카드 정보를 조회하는 SELECT
문이다. 하지만 WHERE
절에 사용되는 card_no
에 인덱스가 적용되어 있지 않다. 이는 tarot_card
테이블이 대량의 데이터를 포함하고 있을 때 검색 성능에 부정적인 영향을 미칠 수 있다. 따라서 card_no
컬럼에 인덱스를 설정하여 검색 성능을 높여야 한다.
WHERE 절에서 사용하는 컬럼 |
인덱스로 등록된 컬럼 |
---|---|
card_no deleted_at |
id card_pack_id |
<aside> 🚨 인덱스의 성능을 확인하기 위해 테스트 DB에 bulk insert로 5000개의 레코드를 추가하여 진행했습니다.
</aside>
인덱스를 적용하기 전에 EXPLAIN
을 통해 현재 쿼리의 실행 계획을 살펴보자.
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
-> Limit: 1 row(s) (cost=554 rows=1) (actual time=7.12..7.12 rows=1 loops=1)
-> Filter: ((tarot_card.card_no = 0) and (tarot_card.deleted_at is null)) (cost=554 rows=53) (actual time=7.12..7.12 rows=1 loops=1)
-> Table scan on tarot_card (cost=554 rows=5301) (actual time=0.104..4.59 rows=3116 loops=1)
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+