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 temporary가 출력되지 않는다.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;