MySQL 엔진이 스토리이지 엔진으로부터 받아온 레코드를 정렬하거나 그룹핑할 때는 내부적인 임시 테이블(Internal temporary table)
을 사용합니다.
일반적으로 MySQL 엔진이 사용하는 임시 테이블은 처음에는 메모리에 생성됐다가 테이블의 크키가 커지면 디스크로 옮겨집니다. 그리고 쿼리 처리가 완료되면 임시 테이블은 자동으로 삭제됩니다.
MySQL 8.0 이전 버전까지는 원본 테이블의 스토리지 엔진과 관계없이 임시 테이블이 메모리를 사용할 때는 MEMORY 스토리지 엔진을 사용하며, 디스크에 저장될 때는 MyISAM 스토리지 엔진을 이용합니다.
하지만 MySQL 8.0 버전 부터는 TempTable 이라는 스토리지 엔진을 사용하고, 디스크에 저장되는 임시 테이블은 InnoDB 스토리지 엔진을 사용하도록 개선 되었습니다.
- ORDER BY와 GROUP BY에 명시된 컬럼이 다른 쿼리
- ORDER BY나 GROUP BY에 명시된 컬럼이 조인의 순서상 첫 번째 테이블이 아닌 쿼리
- DISTINCT와 ORDER BY가 동시에 쿼리에 존재하는 경우 또는 DISTINCT가 인덱스로 처리되지 못하는 쿼리
- UNION 이나 UNION DISTINCT가 사용된 쿼리(select type 컬림이 UNION RESULT인 경우)
- 쿼리의 실행 계획에서 select type이 DERIVED인 쿼리
위의 경우는 실행 계획 Extra 컬럼에 Using temporary
라는 메세지가 표시되는 것을 볼 수 있습니다. 하지만 Using temporary
가 표시되지 않아도 임시 테이블을 사용할 수 있는데, 4 ~ 6번의 경우가 이러한 예시 입니다.
1 ~ 3번의 경우 유니크 인덱스를 가지는 내부적인 임시 테이블 생성
3 ~ 6번의 경우 실행 계획 Extra 컬럼에 Using temporary가 표시되지 않지만 임시 테이블을 생성하여 사용
- 6번의 쿼리 패턴은 유니크 인덱스가 없는 내부 임시 테이블이 생성
- 일반적으로 유니크 인덱스가 있는 내부 임시 테이블은 그렇지 않은 쿼리보다 성능이 상당히 느림
- UNION 이나 UNION ALL에서 SELECT 되는 컬럼 중에서 길이가 512바이트 이상인 크기의 컬럼이 있는 경우
- GROUP BY나 DISTINCT 컬럼에서 512 바이트 이상인 크기의 컬럼이 있는 경우
- 메모리 임시 테이블의 크기가 (MEMORY 스토리지 엔진에서) temp_table_size 또는 max_heap_table_size 시스템 변수보다 크거나 (TempTable 스토리지 엔진에서) temptable_max_ram 시스템 변수 값보다 큰 경우
내부 임시 테이블은 기본적으로 메모리상에 만들어지지만 위의 조건을 만족하면 메모리 임시 테이블을 사용할 수 없게 되고 디스크 기반의 임시 테이블을 사용하게 됩니다.
MySQL 8.0.13 이전 버전까지는 BLOB 이나 TEXT 컬럼을 가진 경우, 임시 테이블을 메모리에 생성하지 못하고 디스크에 생성했다. 하지만 MySQL 8.0.13 버전부터는 BLOB이나 TEXT 컬럼을 가진 임시 테이블에 대해서도 메모리에 임시 테이블을 생성할 수 있게 개선됐다. 하지만 메모리 임시 테이블이 Temptable 스토리지 엔진이 아니라 MEMORY 스토리지 엔진을 사용하는 경우에는 여전히 디스크 임시 테이블을 사용합니다.