Search

Postgresql 인덱싱

개요

기존 쿼리에서 채널의 시청자수를 가져오기 위해 조인문을 하나 넣었는데 쿼리가 너무 눚음
문제는 INDEXING이라 판단하고 EXPLAIN 으로 확인

1차 EXPLAIN 확인

Nested Loop Left Join (cost=4831.31..25993995.35 rows=17453 width=20) -> Hash Right Join (cost=1142.69..1360.65 rows=17453 width=20) Hash Cond: (cl."channelId" = c.id) -> Seq Scan on "channelLive" cl (cost=0.00..199.46 rows=7046 width=8) -> Hash (cost=924.53..924.53 rows=17453 width=20) -> Seq Scan on channel c (cost=0.00..924.53 rows=17453 width=20) -> Memoize (cost=3688.62..3688.63 rows=1 width=4) Cache Key: cl.id Cache Mode: binary -> Subquery Scan on cll (cost=3688.61..3688.62 rows=1 width=4) -> Limit (cost=3688.61..3688.61 rows=1 width=12) -> Sort (cost=3688.61..3688.74 rows=56 width=12) Sort Key: cll_inner."createdAt" DESC -> Seq Scan on "channelLiveLog" cll_inner (cost=0.00..3688.32 rows=56 width=12) Filter: ("channelLiveId" = cl.id)
Bash
복사
EXPLAIN에 의해 가져온 분석을 확인해보면
Nested Loop Left Join에 의해 4831.31..25993995.35 까지 높은 비용이 발생하고 있다.
4831.31은 쿼리가 실행되기전, 첫번째행을 반환하는데 드는 예상비용이고
25993995.35는 모든 쿼리가 반환되는데 드는 예상 총 비용이다.
초단위로 환산할 수 없는 값이지만 체감상 25993995.35라는 비용은 실시간 서비스에서 매우 큰 문제다.
좀 더 자세히 로그를 보면 Seq Scan가 여러번 발생하고 있는데. channelLive와 channelLiveLog에서 전체 스캔이 발생하고 있다. 이는 인덱스가 되지 않았다는 뜻, 다만 channeLive 로그에서 발생하는 총 비용은 199.46로 적지만 channeLiveLog에서 발생하는 비용은 3688.22로 높다.
가장 많은 병목이 발생하는 지점을 찾아서 먼저 인덱스를 생성해준다.
-> Seq Scan on "channelLive" cl (cost=0.00..199.46 rows=7046 width=8)
Bash
복사
-> Seq Scan on "channelLiveLog" cll_inner (cost=0.00..3688.32 rows=56 width=12)
Bash
복사

인덱스 생성

CREATE INDEX idx_channel_live_id ON "channelLiveLog" ("channelLiveId");
Bash
복사

인덱스 생성 후 EXPLAIN

Nested Loop Left Join (cost=1192.37..340599.00 rows=17524 width=21) -> Hash Right Join (cost=1144.29..1362.25 rows=17524 width=21) Hash Cond: (cl."channelId" = c.id) -> Seq Scan on "channelLive" cl (cost=0.00..199.46 rows=7046 width=8) -> Hash (cost=925.24..925.24 rows=17524 width=21) -> Seq Scan on channel c (cost=0.00..925.24 rows=17524 width=21) -> Memoize (cost=48.08..48.09 rows=1 width=4) Cache Key: cl.id Cache Mode: binary -> Subquery Scan on cll (cost=48.07..48.08 rows=1 width=4) -> Limit (cost=48.07..48.07 rows=1 width=12) -> Sort (cost=48.07..48.21 rows=56 width=12) Sort Key: cll_inner."createdAt" DESC -> Index Scan using idx_channel_live_id on "channelLiveLog" cll_inner (cost=0.29..47.79 rows=56 width=12) Index Cond: ("channelLiveId" = cl.id)
Bash
복사

개선

인덱스 추가 전 총 예상 비용은 25,993,995.35
인덱스 추가 후 총 예상 비용은 340,599.00
따라서 총 개선율은 98.7%로 쿼리 실행시간은 크게 단축되었다.
애초에 인덱스를 걸지않는 실수로 인한 일이지만, 인간은 실수를 하기 때문에
EXPLAIN 로그를 확인하여 어느 지점에서 병목이 발생하는지 찾아서 해결해야한다.