출간 준비 중인 < SQL TUNER for PostgreSQL · 기본원리편 >의 미리보기입니다.
동일한 SQL에 대해서도 여러 인덱스 전략이 가능하다. 어느 것이 더 나은지는 시스템의 특성과 다른 SQL들과의 관계를 함께 고려해야 판단할 수 있다.
다음 SQL을 살펴보자. tr_ord_big 테이블에는 두 가지 조건이 사용되고 있다. mbr_id는 조인 조건으로, ord_ymd는 WHERE 절의 필터 조건이다. 두 조건 모두 동등 조건으로 사용되고 있다.
-- [SQL-8-4-2-a]
SELECT t1.mbr_id ,t1.nick_nm ,t1.join_dtm ,t2.ord_ymd ,t2.ord_amt
FROM startdbpg.ms_mbr_big t1
INNER JOIN startdbpg.tr_ord_big t2
ON (t1.mbr_id = t2.mbr_id)
WHERE t1.nick_nm LIKE 'Air%'
AND t2.ord_ymd = '20241221';
SQL
복사
위 SQL에서 tr_ord_big을 위해 다음 두 가지 인덱스를 고려할 수 있다.
•
tx1(mbr_id, ord_ymd): 조인 조건 컬럼을 선두에 배치
•
tx2(ord_ymd, mbr_id): WHERE 조건 컬럼을 선두에 배치
인덱스 컬럼 순서에 따라 tr_ord_big이 각 조인 알고리즘에서 수행할 수 있는 역할이 달라진다.
먼저 tx1(mbr_id, ord_ymd)을 살펴보자. 조인 조건 컬럼을 선두에 둔 구조로, NL 조인에서 tr_ord_big을 드리븐 테이블로 활용할 때 효과적이다. 머지 조인에서는 조인 키(mbr_id)의 정렬을 해결할 수 있다. 하지만 머지 조인에서는 ord_ymd 조건으로 먼저 데이터를 좁히지 못해 성능이 좋지 않을 수 있다.
이제 tx2(ord_ymd, mbr_id)를 살펴보자. WHERE 조건 컬럼을 선두에 배치한 구조다. [SQL-8-4-2-a]는 조인 조건과 WHERE 조건이 모두 동등 조건이다. 이러한 패턴에서는 tx2 인덱스를 다양한 조인 알고리즘에서 효율적으로 활용할 수 있다. NL 조인에서는 드리븐과 드라이빙 테이블 역할 모두에 적합하다. 해시 조인에서는 ord_ymd로 필터링된 데이터를 빌드 입력이나 프로브 입력으로 효율적으로 사용할 수 있다. 머지 조인에서도 ord_ymd로 먼저 필터링된 후 mbr_id가 정렬된 상태를 유지하므로, 조인 키 정렬을 효율적으로 처리할 수 있다. 이처럼 tx2는 여러 조인 알고리즘에 유연하게 대응할 수 있다.
다만 tx2의 이러한 유연성은 [SQL-8-4-2-a]처럼 두 조건이 모두 동등 조건일 때에 가능하다. 만약 ord_ymd가 범위 조건이라면 tx2 인덱스는 NL 조인의 드리븐으로 비효율적일 수 있으며, 이 경우 머지 조인의 정렬도 해결할 수 없다. 따라서 tx2처럼 ‘WHERE 조건을 앞에, 조인 조건을 뒤에’ 두는 패턴을 단순 암기해서는 절대 안 된다.
업무에 따라서는 tx1(mbr_id, ord_ymd)처럼 mbr_id(회원ID) 컬럼을 선두에 둔 인덱스가 더 자주 사용될 가능성이 있다. 회원, 상품, 가맹점처럼 마스터를 식별하는 ID 컬럼은 업무 특성상 여러 SQL에서 조회 조건으로 반복해서 등장한다. 특히 B2C 서비스에서는 ‘특정 회원의 주문/장바구니/포인트/쿠폰 내역’처럼 회원 기반의 조회가 압도적으로 많기 때문에, mbr_id를 선두로 둔 인덱스가 반드시 필요한 경우가 많다.
정리하면, 어느 쪽이 더 ‘정답’인 인덱스 구조라고 단정할 수는 없다. 실제 시스템에서는 개별 SQL 성능의 중요성, 동일 테이블을 사용하는 다른 SQL들과의 관계, 앞으로 추가될 수 있는 SQL 패턴까지 함께 고려해야 한다. 그 과정에서 ‘지금 이 시스템에서는 무엇을 우선순위로 둘 것인가?’를 계속 고민하는 것이 인덱스 설계의 핵심이다.
물론 실무에서 이 모든 요소를 완벽히 고려하는 것은 현실적으로 불가능하다. 다만 이러한 관점들을 염두에 두고 인덱스를 설계하는 습관을 들이다 보면, 자연스럽게 더 나은 판단을 할 수 있게 된다. 완벽하지 않더라도 이런 고민 자체가 인덱스 설계 실력을 키우는 과정이다.
