본문 바로가기
Development/기타 개발관련

선택도가 높은게 좋을까? DB 인덱스 설계 시 '선택도'가 헷갈리는 이유

by Nahwasa 2025. 7. 7.

목차

     

    서론

      최근 작성했던 '주니어 백엔드 개발자가 반드시 알아야 할 실무 지식'을 읽고 떠오른 내 생각들 글을 다시 읽어보고 있었다. 내가 작성한 내용 중 다음과 같은 내용이 있다.

    보통 DB에서 인덱스 걸 때, 선택도가 높은 칼럼을 선택하라고 한다. 예를들어서 ‘성별’ 칼럼에 인덱스를 거는건 딱히 의미 없다. 책에서는 실무적으론 도움이 되는 경우도 있다고 얘기해줘서 좋았다. 예를들어 status 같은게 있고, ‘대기중’, ‘처리중’, ‘완료’ 이런 상태값을 가지는 경우 ‘완료’가 대부분이니 이론적으론 선택도가 낮아도 완료가 아닌 상태를 뽑는데는 인덱스 걸기 좋다는 얘기였다.

     

     

      근데 이 ‘선택도 (selectivity)’ 라는 단어가 뭔가 어색하고 생소하다고 느껴졌다. 그래서 따로 정리도 해둘겸 나만 그렇진 않을 것 같아 구글링을 해보니 역시나 설명이 서로 다른 경우가 꽤 있다.

     

    해외 자료도 마찬가지다.

     

     

    ‘선택도’는 왜 헷갈릴까?

      이런 문제가 발생한데에는, ‘선택도’가 너무 광범위한 단어이기 때문이다. 또 어감상 ‘선택’ + ‘정도’라서, 뭔가 많이 선택될 수록 선택도가 높을 것 같다는 오해에서 발생하기도 할 것 같다. 개인적으로도 ‘선택도’ 보다는 ‘선택성’이라고 표현하는게 더 와닿는다.

    다음 테이블을 보자.

    이름 성별
    황세영
    A
    B
    C
    D

     

     

      일단 우린 두 칼럼 중 인덱스를 무조건 하나 걸어야 한다면 어디에 인덱스를 거는게 이득인지 알고있다. 당연히 위 데이터로만 보면 ‘이름’쪽에 거는게 더 좋다. 그래야 WHERE의 결과 row가 더 적기 때문이다.

     

      예를들어 SELECT * FROM TB WHERE 이름 = ‘황세영’ 의 결과는 1개이고, SELECT * FROM TB WHERE 성별 = ‘남’은 3개이다. 지금은 5개밖에 데이터가 없지만, 이게 500만개였다고 치면 성별로 조건을 걸면 250만개에 근접하게 결과가 나올 것이다.

     

     

    어떤 기준의 ‘선택도’ ?

      여기서 이하 글 설명을 편하게 하기 위해 용어를 몇 개 정의하고 가겠다.

    • 조건절 기준 선택도 = 해당 조건절의 결과 row 수 / 전체 row 수
    • 카디널리티 (cardinality) : 해당 칼럼에서 유니크한 값의 수. 즉, dintinct 결과 수. distinct(이름) = 5, distinct(성별) = 2
    • 카디널리티 기준 선택도 = 카디널리티 / 전체 row 수

    이쯤에서 왜 선택도라는 단어가 혼란을 줄 수밖에 없는지 감이 잡혔을수도 있다.

     

      우선 ‘조건절 기준 선택도’를 따져보면서 이름과 성별 칼럼을 확인해보자.

    SELECT * FROM TB WHERE 이름 = ‘황세영’ 에 대해서는 1/5 = 0.2가 나온다.

    SELECT * FROM TB WHERE 성별 = ‘남’ 에 대해서는 3/5 = 0.6이 나온다.

    즉, 조건절 기준 선택도는 ‘낮을수록’ 좋다.

     

      이번엔 ‘카디널리티 기준 선택도’를 따져보면서 확인해보자.

    distinct(이름) = 5 이므로, 이름에 대해서는 5/5 = 1이 나온다.

    distinct(성별) = 2 이므로, 성별에 대해서는 2/5 = 0.4가 나온다.

    즉, 카디널리티 기준 선택도는 ‘높을수록’ 좋다.

     

      결론적으로 DB 인덱스를 걸기 좋은 조건은 Full scan에서 멀어질수록 좋다. 아무튼 결과가 적게 나오도록 잘 걸러지면 되는거다. 선택도가 높다, 낮다 이런 용어가 중요한게 아니다.

     

      어쨌든 일반적으로는 ‘카디널리티 기준 선택도’로써 DB 인덱스 선택 시 선택도를 많이 얘기한다. 따라서 일반적으로는 ‘높을수록 좋다’가 맞다. 하지만 문맥상 어떤 것에 대한 선택도인지는 스스로가 판단해서 읽어야 한다.

     

     

    구글링 결과나 LLM을 항상 믿을 순 없다.

      위에 예시로 들었던 블로그 글 중에선 카디널리티 기준 선택도를 설명하면서 낮을수록 좋다고 하는 경우도 있다. 이런 이유로 구글링해서 나온 모든 글을 믿으면 오히려 혼란을 겪을 수도 있다.

     

      그럼 LLM은 어떨까? chatGPT 4o에게 물어본 결과는 다음과 같다. 설명 자체는 ‘조건절 기준 선택도’를 하고 있으면서, 높다, 낮다 판단은 ‘카디널리티 기준 선택도’를 기준으로 말하고 있어서 원리는 맞지만, 읽는 입장에선 혼동이 생긴다.

     

      그럼 이제 우린 글들을 보면서 다음과 같이 판단해볼 수 있다.

    • 카디널리티 기준 선택도를 얘기하면서 낮은게 좋다고 말한다 → 헷갈리셨구나
    • 조건절에 대해 말하면서 선택도가 낮은게 좋다고 말한다 → 아 조건절 기준으로 선택도를 얘기하신거네. 그럼 맞지!

     

     

    무조건 카디널리티 기준 선택도가 높은게 좋을까?

      자, 그럼 ‘선택도’ 용어의 헷갈림을 떠나서 인덱스 자체에 대해 한번 얘기해보자. 무조건 카디널리티 기준 선택도가 높을수록 인덱스 걸기 좋을까?

    결제id 처리 상태 ...
    1 완료 ...
    2 완료 ...
    3 완료 ...
    4 완료 ...
    5 완료 ...
    6 완료 ...
    7 완료 ...
    8 대기중 ...
    9 완료 ...

     

      여기서 ‘상태’의 카디널리티 기준 선택도는 ‘성별’ 만큼이나 매우 낮다. 인덱스를 걸기 좋은건 아니다. 근데, 일반적으로 처리 상태는 99%가 ‘완료’이고, 일부분만 ‘대기중’이다. 여기서 ‘대기중’인 녀석들만 따로 조회할 수 있는 API가 있다면 어떨까? 이 경우 이론상으론 ‘성별’ 만큼이나 인덱스를 걸기 안좋은 칼럼이지만, 실제론 ‘대기중’에 대한 ‘조건절 기준 선택도’가 좋으므로, 실무적으로는 인덱스를 걸기 좋은 칼럼이다.

     

     

    정리

      즉, 정답은 없다. 용어에 매몰되지 말고 원리만 이해하면 된다. 선택도 높고, 낮고 이런 것 보다는 실제 사용할 데이터가 얼마나 좁게 데이터를 걸러내는가를 보면 된다.

     

    정리하자면 다음과 같다.

    • 카디널리티 기준 선택도 → 높을수록 좋다 (유니크값 많음). 또한 일반적으로 DB 인덱스 설계 시 선택도는 이걸 말한다.
    • 조건절 기준 선택도 → 낮을수록 좋다 (조건에 해당하는 행이 적음).
    • 실무에서의 예외 → 카디널리티 기준 선택도가 낮아도, 실무 기준으로는 특정 조건절 기준 선택도가 낮아 인덱스를 걸기 좋은 경우도 있다.
    • 결국 중요한건 높다, 낮다 이런 용어가 아니라 얼마나 ‘좁게 잘 걸러지는지’ 이다.

     

     

    references

    댓글