GROUP BY
도 ORDER BY
와 마찬가지로 스트리밍 처리를 할 수 없다.GROUP BY
작업도 인덱스를 사용하는 경우와 못하는 경우로 나눌 수 있다.
GROUP BY
칼럼으로 인덱스가 존재한다면 인덱스를 차례로 읽으며 그루핑을 수행하고 그 결과로 조인을 처리한다.Using index for group-by
가 표시된다.salaries
테이블에 (emp_no, from_date)
로 인덱스가 생성된 경우 아래 쿼리를 살펴보자.
EXPLAIN
SELECT emp_no
FROM salaries
WHERE from_date='1995-03-01'
GROUP BY emp_no;
--|--------|-----|-------|-------------------------------------
id|table |type |key |Extra
1 |salaries|range|PRIMARY|Using where; Using index for group-by
--|--------|-----|-------|-------------------------------------
from_date
)을 사용했기에 레인지 스캔을 할 수 없지만 루스 인덱스 스캔을 한 것을 확인할 수 있다.(emp_no, from_date)
인덱스를 스캔하며 emp_no
의 첫 번째 유일 값(10001) 탐색emp_no=10001
중 from_date=’1995-03-01’
레코드를 인덱스를 사용해 가져온다.(emp_no, from_date)
인덱스에서 emp_no
의 그 다음 유일 값을 가져온다.MySQL 8.0부터는 루스 인덱스 스캔과 동일하게 동작하는 인덱스 스킵 스캔 최적화도 도입됐다. 8.0 이전에는
GROUP BY
절 처리를 위해서만 루스 인덱스 스캔이 사용됐지만 8.0 이후부터는 단순히WHERE
절로만 검색하더라도 인덱스 스킵 스캔이 동작하면서 최적화가 가능해졌다.
GROUP BY
기준 칼럼이 드라이밍 테이블이 있든 없든 인덱스를 사용하지 못할 때는 임시 테이블을 사용해 처리된다.Using temporary
가 표시된다.DISTINCT
처리가 MIN()
, MAX()
, COUNT()
같은 집합 함수와 함께 사용하는 경우와 아닌 경우에 DISTINCT
가 영향을 미치는 범위가 달라진다.DISTINCT
가 사용될 때 인덱스를 사용하지 못하면 항상 임시 테이블이 필요하다.
Using temporar
y가 출력되지 않는다.SELECT
되는 레코드 중 유니크한 것만 가져오고자 하면 GROUP BY
와 동일한 방식으로 처리된다.
SELECT DISTINCT emp_no FROM salaries;
SELECT emp_no FROM salaries GROUP BY emp_no;
DISTINCT
는 조회하는 레코드(튜플)를 유니크하게 조회하는 것이니 특정 칼럼만 유니크하게 조회할 수는 없다.DISTINCT
가 집합 함수와 함께 사용되면 집합 함수 인자로 전달된 칼럼값이 유니크한 것들을 가져온다.SELECT COUNT(DISTINCT s.salary)
FROM employees e, salaries s
WHERE e.emp_no=s.emp_no
AND e.emp_no BETWEEN 10001 AND 10100;
salary
칼럼 값만 저장하기 위한 임시 테이블을 만들어 사용한다.
Using temporary
를 표시하지 않지만 말이다.salary
칼럼에는 유니크 인덱스가 생기기에 레코드 건수가 많아진다면 상당히 느려질 수 있다.DISTINCT
를 처리할 때는 인덱스 풀 스캔 또는 레인지 스캔하면서 임시 테이블 없이 최적화를 수행할 수 있다.SELECT COUNT(DISTINCT emp_no) FROM employees;