인덱스와 카디널리티

d3fau1t·2021년 12월 5일
3

DB

목록 보기
2/2
post-thumbnail

인덱스 관련 글을 작성하면서 과거에 인덱스 작업을 할 때 어떤 방식으로 인덱스를 선정하였는지 고민하면서 카디널리티와 관련된 내용을 찾아본적 있는데, 관련 내용을 글로 남기기 위해 이 포스트를 작성하게되었다.

사건의 발단

서비스 장애 알람이 발생했다.
서비스의 사용자가 늘어나면서 이전에 안보이던 이슈가 하나씩 발견되고있다.
기분 좋지만 심장에 안좋다.
왜그런지 확인하기위해 아마존 콘솔에 접속했다.

딱봐도 인덱스 제대로 안타고있을 것 같다.
멀티컬럼 인덱스가 걸려있어야 할 것 같은데.. 확인해보니 goods_id, status, created_at 각 컬럼에 1개씩 인덱스가 걸려있었다.

인덱스 전략 세우기

서비스에서는 3개의 컬럼을 같이 쓰고있으니 뭐하나 빼지말고 인덱스 전략을 세워야한다.

columndescription
goods_id상품목록의 ID값을 외래키로 참조하는 컬럼
상품 수는 200가지 정도된다. 카디널리티가 status에 비하여 높다.
status상품 주문상태이다
상태는 4가지로 관리된다. 카디널리티가 goods_id에 비하여 낮다.
created_atrow 생성 시점이다.
timestamp값이 ms 단위까지 기록된다.

카디널리티가 높은 순서대로 인덱스를 걸어주면 효율적일 것 같다.

카디널리티?

위에서 카디널리티라는 키워드를 이야기했는데..

특정 컬럼을 기준으로 중복도가 높으면 카디널리티가 낮고, 중복도가 낮으면 카디널리티가 높다고 한다.

테이블 전체 row에서 얼마나 중복되는가에 대한 지표로 활용할 수 있다.
이는 상대적인 수치이다.

셀 수 없는 카디널리티는 아무리 값이 커도 셀 수 없는 카디널리티보단 아래인 것 같다.

셀 수 있음

예를들어 현재 조회하려는 테이블에서 goods_id와 status의 중복된 값을 배제하고 조회할경우 얼마나 많은 가지 수가 나오는지 확인해보았다.

SELECT goods_id, count(goods_id) FROM TABLE_NAME group by goods_id;
-- goods_id는 200 개 있다.

SELECT status, count(status) FROM TABLE_NAME group by status;
-- status는 4 개 있다. 

이런 경우는 카디널리티를 셀 수 있다.

셀 수 없음

created_at의 경우 unique하진 않겠지만 row 생성시점마다 달라지고 추가될때마다 카디널리티가 높아지는 상황이 발생한다.
특정 시점을 기준으로 카디널리티를 구할 수 있겠지만 group by counting을 한다거나 중복도를 체크하기위해선 많은 비용이 들 것이다.

이러한 경우는 셀 수 없는 카디널리티라고 생각하고, 셀 수 없는 카디널리티는 셀 수 있는 카디널리티 goods_id보다 카디널리티가 높다곤 할 수 없다.

인덱스 걸어주기

작업전 유의사항

  • 인덱스 걸기전에 테스트/개발 환경에서 먼저 걸어보자
    • 만들어놓은 인덱스가 제대로 작동 안할 수 있으니.. 꼭..
  • 인덱스 걸어주려는 테이블에 트랜잭션이 많이 발생하는 시간대에는 인덱스 걸지말자
    • 테이블 락걸린다
      • show full processlist 로 인덱싱 쿼리 찾아서 kill 해줘야함.
    • 사용시간이 적은 때에 걸어주자
    • 걸었다고 해도 제대로 작동 안하면 드랍하는데 시간 더 걸린다

created_at 으로 range를 잡고 시작

1안

오랜기간동안 쌓인 데이터를 보존하면서 운영해야한다면 created_at으로 최근 특정 기간을 먼저 걸러버린 다음에 필요한 인덱스를 추가하는 것도 방법일 것 같지만...

created_at -> goods_id -> status

로그 데이터를 기록하는 테이블의경우 일정 기간이 지나면 row를 날려버리기 때문에 created_at으로 잡아도 큰 의미가 없을 수 있다고 생각한다..
심지어 created_at은 카디널리티가 비교적 낮다고 판단했기 때문에 앞에 오는게 바람직하지 않다고 생각한다.

그래서 조금 다른방식으로 접근해보았다.

특정 컬럼을 기준으로 잡고 시작

2안

Cron 서비스가 돌면서 보관시점으로부터 일정 기간이 지난 row는 이미 날려주었다고 생각했을 때, 카디널리티가 높은 순서부터 인덱스를 걸어주면 어떨까 생각했다.

goods_id -> status -> created_at

결과 확인

Before

before

After

After

조회하는 row 수가 압도적으로 줄었다.

결론

카디널리티에 기반한 인덱싱 전략을 세우고 실제 서비스에서 어떻게 작동하는지 알아볼 수 있었다.

profile
웹 백엔드 합니다.

1개의 댓글

comment-user-thumbnail
2022년 12월 16일

셀 수 없는 카디널리티는 아무리 값이 커도 셀 수 없는 카디널리티보단 아래인 것 같다.

요 문장 한번 정리해주시면 좋을 것 같아요! 아래 설명하고 매끄럽게 읽히지 않았습니다 ㅠㅠ

답글 달기