잘못된 기대
일반적으로 'count(*)' 쿼리가 'select *' 보다 가벼울 것이라 기대한다. 하지만 대부분은 성능이 거의 동일한 경우가 많다. 또한 limit 조건 없이 사용되는 count 쿼리와 달리 select 쿼리의 경우 일반적으로 limit 조건이 걸린 후 사용되는 경우가 많기 때문에 성능면에서 count가 더 안좋은 경우가 있다.
심지어 ORM에서 자동 생성된 쿼리를 실행하면 하기 코드와 같이 distinct 쿼리가 자동 생성되어 사용되는 경우도 있다. count(*)의 경우에는 레코드 건수만 확인하면 되지만 count(distinct column)은 임시 테이블을 생성해 테이블의 레코드를 임시 테이블로 중복을 제거하면서 복사 후 레코드 건수를 반환하기 때문에 성능적으로 보면 훨씬 안좋다.
select count(distinct(id)) as counter
from exam_tab
where exam_col = ?;
다음 두 쿼리가 있다고 가정해보자. 이 두 쿼리는 커버링 인덱스를 탈 수는 없고 idx_col 컬럼을 이용해서 대상 레코드를 찾은 후 no_idx_col를 비교한 후 결과를 반환하게 될 것이다. 이 경우에는 두 쿼리의 성능은 거의 동일하다고 볼 수 있다. 물론 select count(*)는 결과값 바이트 수가 적기 때문에 select * 보다 네트워크 사용량은 select * 이 더 많다.
-- idx_col : 인덱스가 걸린 컬럼
-- no_idx_col : 인덱스가 걸리지 않은 컬럼
select count(*)
from exam_tab
where idx_col = 'A'
and no_idx_col = 'B'
select *
from exam_tab
where idx_col = 'A'
and no_idx_col = 'B'
count 쿼리 성능 개선
정확한 레코드 건수를 확인해야 할 때 최고의 성능 튜닝은 다음과 같이 커버링 인덱스 실행계획으로 쿼리가 처리되도록 하면 된다.
select count(*)
from exam_tab
where idx_col1 = ?
and idx_col2 = ?
select count(idx_col2)
from exam_tab
where idx_col1 = ?
하지만 하기 두 쿼리는 커버링 인덱스로 처리될 수가 없다. 즉 모든 쿼리를 커버링 인덱스로 처리할 수는 없기 때문에 꼭 필요한 경우에만 사용해야 한다.
select count(*)
from exam_tab
where idx_col1 = ?
and no_idx_col2 = ?
select count(no_idx_col2)
from exam_tab
where idx_col1 = ?
사실 최고의 튜닝은 제거이다. 예를 들어 count(*) 쿼리가 꼭 필요한 정보가 아니거나 다른 요구사항으로 변경이 가능하다면 count(*) 쿼리를 제거하는 것도 하나의 방법이 될 수 있다. 만약 제거가 불가능하다면 count(*)과 같이 전체 조회를 하기보다는 표시할 페이지 번호만큼만 보여주는 방식을 이용해 부분 레코드 건수만 조회할 수 있도록 하는 것도 방법이 될 수 있다.
-- 레코드 부분 건수 확인
select count(*)
from (select 1 from exam_tab limit 200) tab;
Tip)
제거 대상
- where 조건 없는 count(*)
- where 조건에 일치하는 건수가 많은 count(*)
인덱스 최적화 대상
- 정확한 count(*)가 필요한 경우
- count(*) 대상이 소량인 경우
- where 조건이 인덱스로 처리될 수 있는 경우
Reference
- Real MySQL - 이성욱님, 백은빈님
'Study > [무럭무럭 시즌 2] Real MySQL 8.0' 카테고리의 다른 글
무럭무럭 STUDY - LEFT JOIN 주의사항 그리고 튜닝 (MySQL) (0) | 2024.09.28 |
---|---|
무럭무럭 STUDY - 끄적끄적 (MySQL) (0) | 2024.09.28 |
무럭무럭 STUDY - CHAR vs VARCHAR vs TEXT (MySQL) (0) | 2024.09.21 |
무럭무럭 STUDY - InnoDB 스토리지 엔진 아키텍처 (0) | 2023.09.01 |
무럭무럭 STUDY - MySQl 엔진 아키텍처 (0) | 2023.08.19 |