AND, OR에서 Composite Index가 사용되는 방법
AND나 OR이 WHERE 절에 포함될 때는 여러 조건에 따라 예상치 못 하게 Index가 적용되지 않을 수 있습니다. 그중에서도 가장 주의해야 할 부분이 Composite Index입니다.
🐜 Composite Index가 있을 경우 앞에 부분이 조건에 포함돼야 한다
아래와 같은 Composite Index가 있을 때...
CREATE INDEX idx_user_status ON orders(user_id, status);
처음 들어간 COL인 user_id가 없는 WHERE 절은 해당 Index가 적용되지 않습니다.
SELECT * FROM orders WHERE status = 'PENDING';
또 정말 헷갈리게도 2개 COL이 모두 포함돼도 순서가 안 맞으면 적용되지 않습니다.
SELECT * FROM orders WHERE status = 'PENDING' AND user_id = 123;
🐜 Composite Index는 OR에는 적용되지 않는다
Composite Index는 기본적으로 앞에 있는 COL을 먼저 Sorting하고 같은 앞에 있는 부분 안에서 뒤에 있는 COL을 Sorting 하기 때문에 뒤에 있는 COL을 기준으로 뭔가를 해야 할 경우 Composite Index를 사용할 수 없습니다. 이 말은 OR 조건이 있을 경우 Composite Index를 사용할 수 없다는 겁니다.
SELECT * FROM orders WHERE user_id = 123 OR status = 'PENDING';
OR은 가능하면 UNION ALL 로 쪼개기
UNION ALL은 2개의 SELECT 문의 결과를 합치는 연산자입니다.
SELECT column1 FROM table1
UNION ALL
SELECT column1 FROM table2
;
중복을 제거해 주지 않기 때문에 OR 조건으로 합쳐진걸 항상 쪼갤 수 있는 건 아니지만 쪼갤 수 있다면 쪼개는 게 성능에 더 유리합니다.
- 실행 계획이 훨씬 간단합니다. (그래서 적절한 Index를 사용할 확률이 더 높습니다.)
- (일부) 2개의 Query가 병렬로 실행될 수 있습니다.
가능하다면 Boolean Algebra를 써서 조건 간단하게 하기
AND / OR 조건이 복잡해 지면 질수록 놓치기 쉬운 부분이지만, 여러 법칙을 써서 같은 결과를 주는데 훨씬 간단하게 바꿀 수 있습니다.
요 2개는 분배 법칙을 써서 바꾼건데, 아래 거가 UNION으로 최적화를 할 수 있어 성능이 더 좋습니다.
A AND (B OR C)
(A AND B) OR (A AND C)
AND / OR 조건이 아예 필요 없어지는 경우도 있습니다. 아래 2개는 모두 A 하나만 있는 것도 똑같습니다.
A OR (A AND B)
A AND (A OR B)
학창 시절에 배웠던 드모르간의 법칙을 쓸 수도 있습니다.
NOT (A OR B)
NOT A AND NOT B
NOT (A AND B)
NOT A OR NOT B
SELECT 최대한 줄여서 Covering Index 사용하기
Covering Index는 Query가 Index 자체에 모든 COL이 있어서 실제 DB를 접근할 필요 없이 처리 완료되는 Index를 말합니다. 예를 들어 아래와 같은 SELECT 문과 Index가 있을 때, SELECT 문에 있는 모든 COL이 Index에 있기 때문이 이 Index는 Covering Index가 됩니다.
SELECT order_id, order_date FROM orders WHERE customer_id = ?;
CREATE INDEX idx_order ON orders (customer_id, order_id, order_date);
당연히 모든 COL을 SELECT 한다면 Covering Index를 사용할 수 없고, 최대한 필요한 COL을 SELECT 할수록 Covering Index를 쓸 확률이 올라갑니다.
'👨💻 프로그래밍 > 📦 Backend' 카테고리의 다른 글
MSA 환경에서 Circuit Breaker를 쓰는 이유, 그럼에도 발생하는 문제 Bulkhead로 해결하기 (0) | 2023.09.24 |
---|---|
트랜잭션 격리수준 (Transaction Isolation)에 따른 데이터 불일치 현상 (0) | 2023.07.18 |
왜 VARCHAR 대신 LOB를 써야 할까? DB가 LOB를 최적화하는 방법 (0) | 2023.07.14 |
Reflection은 객체지향에 반할까? (0) | 2023.07.13 |
DDD Aggregate (애그리게이트) 알아보기 (0) | 2023.06.18 |