Queries

데이터를 얼마나 적게 조회할 것인지가 핵심

  • 쿼리를 작성할 때, 항상 데이터를 얼마나 적게 조회할 것인가를 생각하면서 작성해야 함
  • 컬럼의 개수는 성능에 영향
    • 특정 컬럼의 데이터가 너무 큰 경우에 성능에 영향을 줌
    • 데이터가 너무 크지 않더라도, 컬럼의 개수가 많아지면 그만큼 데이터를 조회하고 그 결과를 WAS 에서 사용하려면 네트워크를 거치기 때문에 패킷의 크기가 상승하고, 결국 비용도 상승하게됨
  • 데이터를 적게 조회하기 위해서는 범위를 어떻게 줄일 것인가를 고려해야 함
  • where 문을 작성할 때는 항상 인덱스를 생각하면서 작성해야 함

Indexing

데이터베이스는 Cost Based 이기 때문에, 인덱스 비용과 Table Full Scan 비용을 알아서 고려해서 인덱스가 걸려있다 하더라도 Table Full Scan 시 성능이 더 뛰어나다면 그것을 적용한다.

  • 날짜 조건 시 LocalDateTime 으로 처리
    • Ex. 2022-08-01 00:00:00 ~ 2022-08-02 23:59:59
    • 애플리케이션에서 string 타입으로 바인딩하게 되면 컨버팅 과정이 일어나서 인덱스가 안 탈 수 있음
  • 복합 인덱스에 날짜(범위) 인덱스가 있다면 뒤에 생성해야 함
  • where, join, order by 등과 관련된 사용 빈도가 높고 키 값의 선별도가 좋은 컬럼을 대상으로 인덱스를 생성해야 함
  • where 조건에 case 문 같은 것은 사용하지 않는 것이 좋음
    • case 문을 계산하고나서 뒤에 있는 and 문들을 실행한다. case 문 같은 것은 쿼리를 던질 때마다 계산한다.
  • 선택한 키의 검색 일치율이 10% 미만인 경우에는 Index 를 사용하는 것이 좋고, 그 이상일 경우에는 풀 스캔 방식이 더 좋을 수 있음
  • LIKE %~는 조심 (table scan 이여서 성능 감소) % 는 뒤에만 사용하도록 해야함
  • Foreign key (1:1 매핑)이 많을 때 -> 클러스터, 논클러스터 인덱스 둘 다 상관 없음 (상황에 따라 클러스터인덱스 사용)
  • Foreign key (1:N 매핑)이 많을 때 -> 클러스터 인덱스 사용
  • not 연산자는 인덱스를 사용할 수 없기 때문에 긍정문으로 변경
  • insert, delete 등 데이터의 변경이 많은 컬럼은 인덱스를 걸지 않은 편이 좋음. 인덱스를 만드는데 시간과 저장공간이 소비되고 만들고 난 후에도 추가적인 공간이 필요. 데이터를 변경 (insert, update, delete)를 하면 (특히 insert) 인덱스를 다시 조정해야하기 때문에 자원이 많이 소모됨
  • 가급적 단일 인덱스보다는 복합 인덱스가 좋음
    • 단일 인덱스는 자칫 하다가 내가 추가로 작성한 쿼리가 인덱스 때문에 오히려 성능이 안나올 수도 있음
    • 단일 인덱스로인한 내가 작성한 쿼리에 성능 사이드 이펙트가 발생할 수 있음
    • 복합 인덱스 생성시, 컬럼의 위치(순서)가 상당히 중요하기 때문에 신중하게 결정해야 함. 즉, 두 번째 컬럼은 첫 번째 컬럼의 정렬에 의존하고, 세 번째 컬럼은 두 번째 컬럼의 정렬에 의존함

분포도

분포도가 좋은 컬럼(키값의 선별도가 좋은 컬럼)을 대상으로 인덱스를 생성하는 것이 좋다.

이름, 나이, 성별 세 가지의 필드를 갖고 있는 테이블을 생각해보자. 이름은 온갖 경우의 수가 존재할 것이며 나이는 INT 타입을 갖을 것이고, 성별은 남, 녀 두 가지 경우에 대해서만 데이터가 존재할 것임을 쉽게 예측할 수 있다.

이 경우에는 이름에만 인덱스를 생성하는 것이 좋다. 값의 range 가 적은 성별은 인덱스를 읽고 다시 한 번 디스크 I/O 가 발생하기 때문에 그 만큼 비효율적인 것이다.

성별의 경우 남자, 여자이니 선택 확률이 50% 로 분포도가 아주 크고 좋지 않다고 말한다. 분포도 값이 크면(분포도가 안좋으면) 인덱스 검색의 범위가 많아지므로 인덱스 스캔에 불리하다.

  • 분포도가 넓다 = 분포도 값이 크다 = 분포도가 안좋다.
  • 분도포가 좁다 = 분포도 값이 작다 = 분포도가 좋다