MySQL 의 두 가지 임시 테이블

다음으로 이동:http://mysql.taobao.org/monthly/2016/06/07/
외부 임시 테이블
CREATE TEMPORARY TABLE 을 통 해 만 든 임시 표를 외부 임시 표 라 고 합 니 다.이 임시 시 계 는 현재 사용자 에 게 만 보 입 니 다. 현재 세 션 이 끝 날 때 이 임시 시 계 는 자동 으로 종 료 됩 니 다.이 임시 표 의 이름 은 임시 표 와 같 을 수 있 습 니 다. (같은 이름 이 아 닌 임시 표 는 임시 표 가 삭 제 될 때 까지 현재 세 션 을 볼 수 없습니다.)
내부 임시 테이블
내부 임시 표 는 특수 경량급 의 임시 표 로 성능 최적화 에 사용 된다.이 임시 표 는 MySQL 에 의 해 자동 으로 생 성 되 고 일부 작업 의 중간 결 과 를 저장 합 니 다.이런 조작 은 최적화 단계 나 집행 단계 에 포 함 될 수 있다.이 내부 표 는 사용자 에 게 는 보이 지 않 지만 EXPLAIN 이나 SHOW STATUS 를 통 해 MYSQL 이 내부 임시 표를 사용 하여 어떤 작업 을 수행 하 는 데 도움 을 주 었 는 지 확인 할 수 있 습 니 다.내부 임시 표 는 SQL 문장의 최적화 과정 에서 매우 중요 한 역할 을 하고 MySQL 의 많은 조작 은 내부 임시 표 에 의존 하여 최적화 해 야 한다.그러나 내부 임시 표를 사용 하려 면 표 와 중간 데이터 의 액세스 대 가 를 만들어 야 하기 때문에 사용 자 는 SQL 문 구 를 쓸 때 임시 표를 사용 하지 않도록 해 야 한다.
내부 임시 표 는 두 가지 유형 이 있 습 니 다. 하 나 는 HEAP 임시 표 입 니 다. 이 임시 표 의 모든 데 이 터 는 메모리 에 존재 합 니 다. 이 표 의 조작 에 대해 서 는 IO 작업 이 필요 하지 않 습 니 다.다른 하 나 는 OnDisk 임시 표 인 데, 말 그대로 이 임시 표 는 데 이 터 를 디스크 에 저장 합 니 다.OnDisk 임시 표 는 중간 결과 가 비교적 큰 조작 을 처리 하 는 데 쓰 인 다.HEAP 임시 테이블 에 저 장 된 데이터 가 MAX 보다 크 면HEAP_TABLE_SIZE (자세 한 내용 은 MySQL 매 뉴 얼 의 시스템 변수 부분 을 참고 하 십시오), HEAP 임시 표 는 자동 으로 OnDisk 임시 표 로 변 환 됩 니 다.OnDisk 임시 표 는 5.7 에서 INTERNAL 을 통과 할 수 있 습 니 다.TMP_DISK_STORAGE_ENGINE 시스템 변 수 는 MyISAM 엔진 이나 InnoDB 엔진 을 선택 합 니 다.
이 글 은 주로 어떤 조작 이 내부 임시 표 에 이 용 될 수 있 는 지 를 소개 한다.만약 에 사용자 가 SQL 문 구 를 쓸 때 내부 임시 표를 최대한 적 게 사용 하여 조회 최 적 화 를 할 수 있다 면 조회 집행 의 효율 을 효과적으로 높 일 수 있다.
우선 표 t1 을 정의 합 니 다.
CREATE TABLE t1( a int, b int); INSERT INTO t1 VALUES(1,2),(3,4);

아래 의 모든 조작 은 표 t1 을 바탕 으로 예 를 들 었 다.
SQL 구문 에 SQL 사용 하기BUFFER_RESULT hint SQL_BUFFER_RESULT 는 주로 MySQL 이 표 의 자 물 쇠 를 가능 한 한 빨리 풀 도록 하 는 데 쓰 인 다.데이터 양 이 많 으 면 클 라 이언 트 에 데 이 터 를 보 내 는 데 시간 이 오래 걸 리 기 때문에 데 이 터 를 임시 표 에 버퍼 링 하면 읽 기 잠 금 시간 을 효과적으로 줄 일 수 있 습 니 다.예 를 들 면:
    mysql> explain format=json select SQL_BUFFER_RESULT * from t1;
    EXPLAIN
    {
      "query_block": {
        "select_id": 1,
        "cost_info": {
          "query_cost": "2.00"
        },
        "buffer_result": {
          "using_temporary_table": true,
          "table": {
            "table_name": "t1",
            "access_type": "ALL",
        ...

만약 SQL 문장 에 DERIVED 가 포함 되 어 있다 면TABLE。 5.7 에서 새로운 최적화 방식 을 채 택 했 기 때문에 우 리 는 set optimizer 를 사용 해 야 한다switch=’derived_merge = off '는 derived table 을 외부 Query 에 통합 하 는 것 을 금지 합 니 다.예 를 들 면:
    mysql> explain format=json select * from (select * from t1) as tt;
    EXPLAIN
    {
      "query_block": {
        "select_id": 1,
        "cost_info": {
          "query_cost": "2.40"
        },
        "table": {
          "table_name": "tt",
          "access_type": "ALL",
          ...
          "materialized_from_subquery": {
            "using_temporary_table": true,
        ...

만약 우리 가 시스템 표를 조회 한다 면 시스템 표 의 데 이 터 는 내부 임시 표 에 저 장 될 것 이다.현재 EXPLAIN 을 사용 하여 시스템 시트 데 이 터 를 읽 는 지 내부 임시 표 에 이용 해 야 하 는 지 확인 할 수 없 지만 SHOW STATUS 를 통 해 내부 임시 표 에 이용 되 었 는 지 확인 할 수 있 습 니 다.예 를 들 면:
    mysql> select * from information_schema.character_sets;
    mysql> show status like 'CREATE%';

DISTINCT 문구 가 최적화 되 지 않 으 면 DISTINCT 문구 가 GROUP BY 작업 으로 최적화 되 거나 UNIQUE INDEX 를 이용 하여 DISTINCT 를 제거 하면 내부 임시 표 가 사 용 됩 니 다.
    mysql> explain format=json select distinct a from t1;
    EXPLAIN
    {
    {
      "query_block": {
        "select_id": 1,
        "cost_info": {
          "query_cost": "1.60"
        },
        "duplicates_removal": {
          "using_temporary_table": true,
        ...

검색 에 ORDER BY 문구 가 있 고 최적화 되 지 않 습 니 다.다음 몇 가지 상황 은 내부 임시 표 캐 시 중간 데 이 터 를 이용 하여 중간 데 이 터 를 정렬 합 니 다.1) 연결 표 에 BNL (Batched Nestloop) / BKA (Batched Key Access) 를 사용 하면 다음 과 같다.
1) BNL 은 기본적으로 열 려 있다
mysql> explain format=json select * from t1, t1 as t2 order by t1.a;
EXPLAIN
{
  "query_block": {
  "select_id": 1,
  "cost_info": {
    "query_cost": "22.00"
  },
  "ordering_operation": {
    "using_temporary_table": true,
  ...

2)) BNL 을 끄 면 ORDER BY 는 filesort 를 직접 사용 합 니 다.
mysql> set optimizer_switch='block_nested_loop=off';
Query OK, 0 rows affected (0.00 sec)
mysql> explain format=json select * from t1, t1 as t2 order by t1.a;
EXPLAIN
{
   "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "25.00"
    },
    "ordering_operation": {
      "using_filesort": true,
    ...

2) ORDER BY 의 열 은 실행 계획 의 첫 번 째 연결 표 의 열 에 속 하지 않 습 니 다.예 를 들 면:
mysql> explain format=json select * from t as t1, t as t2 order by t2.a;
EXPLAIN
{
   "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "25.00"
    },
    "ordering_operation": {
      "using_temporary_table": true,
    ...

3) ORDER BY 의 표현 식 이 복잡 한 표현 식 이 라면.
그렇다면 어떤 ORDER BY 표현 식, MySQL 은 복잡 한 표현 식 이 라 고 생각 합 니까?
1)) 정렬 식 이 SP 또는 UDF 라면.예 를 들 면:
drop function if exists func1;
delimiter |
create function func1(x int)
returns int deterministic
begin
declare z1, z2 int;
set z1 = x;
set z2 = z1+2;
return z2;
end|
delimiter ;
explain format=json select * from t1 order by func1(a);
{
    "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "2.20"
    },
    "ordering_operation": {
      "using_temporary_table": true,
    ..

2)) ORDER BY 의 열 은 집합 함 수 를 포함한다
실행 계획 을 간소화 하기 위해 저 희 는 INDEX 를 이용 하여 GROUP BY 문 구 를 최적화 합 니 다.예 를 들 면:
  create index idx1 on t1(a);
  explain format=json SELECt a FROM t1 group by a order by sum(a);
  | {
       "query_block": {
        "select_id": 1,
        "cost_info": {
          "query_cost": "1.20"
        },
        "ordering_operation": {
          "using_temporary_table": true,
          "using_filesort": true,
          "grouping_operation": {
            "using_filesort": false,
        ...
  drop index idx1 on t1;

3)) ORDER BY 의 열 에는 SCALAR SUBQUERY 가 포함 되 어 있 습 니 다. 물론 이 SCALAR SUBQUERY 는 최적화 되 지 않 았 습 니 다.예 를 들 면:
explain format=json select (select rand() from t1 limit 1) as a from t1 order by a;     
| {
      "query_block": {
        "select_id": 1,
        "cost_info": {
          "query_cost": "1.20"
        },
        "ordering_operation": {
          "using_temporary_table": true,
          "using_filesort": true,
            ...

4) 조 회 는 ORDER BY 와 GROUP BY 문 구 를 가지 고 있 지만 두 문 구 는 열 이 다르다.
주의: 5.7 이 라면 sqlmode 는 비 only 로 설정full_group_by 모드, 그렇지 않 으 면 잘못 보고 할 수 있 습 니 다.
마찬가지 로 실행 계획 을 간소화 하기 위해 저 희 는 INDEX 를 이용 하여 GROUP BY 문 구 를 최적화 합 니 다.예 를 들 면:
set sql_mode='';
create index idx1 on t1(b);
explain format=json select t1.a from t1 group by t1.b order by 1;
| {
     "query_block": {
        "select_id": 1,
        "cost_info": {
          "query_cost": "1.40"
        },
    "ordering_operation": {
          "using_temporary_table": true,
          "using_filesort": true,
          "grouping_operation": {
            "using_filesort": false,
    ...
drop index idx1 on t1;

검색 이 GROUP BY 문 구 를 가지 고 있 고 최적화 되 지 않 는 다 면.아래 의 몇 가지 상황 은 내부 임시 테이블 캐 시 중간 데 이 터 를 이용 하여 중간 데 이 터 를 GROUP BY 로 진행 합 니 다.1) 연결 표 에 BNL (Batched Nestloop) / BKA (Batched Key Access) 를 사용 하면.예 를 들 면:
    explain format=json select t2.a from t1, t1 as t2 group by t1.a;
    | {
        "query_block": {
        "select_id": 1,
        "cost_info": {
          "query_cost": "8.20"
        },
        "grouping_operation": {
          "using_temporary_table": true,
          "using_filesort": true,
          "cost_info": {
            "sort_cost": "4.00"
        ...

2) 그룹 BY 의 열 이 실행 계획 의 첫 번 째 연결 표 에 속 하지 않 는 다 면.예 를 들 면:
    explain format=json select t2.a from t1, t1 as t2 group by t2.a;
    | {
        "query_block": {
        "select_id": 1,
        "cost_info": {
          "query_cost": "8.20"
        },
        "grouping_operation": {
          "using_temporary_table": true,
          "using_filesort": true,
          "nested_loop": [
        ...

3) GROUP BY 구문 에서 사용 하 는 열 이 ORDER BY 구문 에서 사용 하 는 열 과 다르다 면.예 를 들 면:
    set sql_mode='';
    explain format=json select t1.a from t1 group by t1.b order by t1.a;
    | {
       "query_block": {
        "select_id": 1,
        "cost_info": {
          "query_cost": "1.40"
        },
        "ordering_operation": {
          "using_filesort": true,
          "grouping_operation": {
            "using_temporary_table": true,
            "using_filesort": false,
        ...

4) 그룹 BY 가 ROLLUP 을 가지 고 있 고 다 중 표 외 연결 을 기반 으로 한다 면.예 를 들 면:
    explain format=json select sum(t1.a) from t1 left join t1 as t2 on true group by t1.a with rollup;
    | {
        "query_block": {
        "select_id": 1,
        "cost_info": {
          "query_cost": "7.20"
        },
        "grouping_operation": {
          "using_temporary_table": true,
          "using_filesort": true,
          "cost_info": {
            "sort_cost": "4.00"
          },
        ...

5) GROUP BY 문 구 를 사용 하 는 열 이 SCALAR SUBQUERY 에서 나 왔 고 최적화 되 지 않 았 다 면.예 를 들 면:
    explain format=json select (select avg(a) from t1) as a from t1 group by a;
    | {
        "query_block": {
        "select_id": 1,
        "cost_info": {
          "query_cost": "3.40"
        },
        "grouping_operation": {
          "using_temporary_table": true,
          "using_filesort": true,
          "cost_info": {
            "sort_cost": "2.00"
          },
        ...

IN 표현 식 을 semi - join 으로 변환 하여 최적화 1) semi - join 실행 방식 이 Materialization 이 라면:
set optimizer_switch='firstmatch=off,duplicateweedout=off';
explain format=json select * from t1 where a in (select b from t1);
| {
    "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "5.60"
    },
    "nested_loop": [
      {
         "rows_examined_per_scan": 1,
              "materialized_from_subquery": {
                "using_temporary_table": true,
                "query_block": {
                  "table": {
                    "table_name": "t1",
                    "access_type": "ALL",

    ... 

2) semi - join 의 실행 방식 이 Duplicate Weedout 이 라면:
    set optimizer_switch='firstmatch=off';
    explain format=json select * from t1 where a in (select b from t1);
     | {
        "query_block": {
        "select_id": 1,
        "cost_info": {
          "query_cost": "4.80"
        },
        "duplicates_removal": {
          "using_temporary_table": true,
          "nested_loop": [
                {
        ...

검색 어 에 UNION 이 있 으 면 MySQL 은 내부 임시 표를 이용 하여 UNION 작업 의 중복 을 없 애 는 데 도움 을 줄 것 이다.예 를 들 면:
    explain format=json select * from t1 union select * from t1;
    | {
        "query_block": {
        "union_result": {
          "using_temporary_table": true,
          "table_name": "",
        ...

검색 어 를 다 중 표 로 업데이트 하면.여기 서 Explain 은 내부 임시 표 가 이용 되 는 것 을 볼 수 없 기 때문에 status 를 봐 야 합 니 다.예 를 들 면:
update t1, t1 as t2 set t1.a=3;
show status like 'CREATE%';

집합 함수 에 다음 과 같은 함수 가 포함 되 어 있 으 면 내부 임시 표 도 이용 된다.1) count (distinct *) 예:
    explain format=json select count(distinct a) from t1;

2) group_concat 예:
    explain format=json select group_concat(b) from t1;

한 마디 로 하면 위 에 10 가지 상황 이 열거 되 어 있 습 니 다. MySQL 은 내부 임시 표를 이용 하여 중간 결과 캐 시 를 합 니 다. 데이터 양 이 많 으 면 내부 임시 표 는 데 이 터 를 디스크 에 저장 합 니 다. 그러면 성능 에 영향 을 줄 수 있 습 니 다.가능 한 한 성능 손실 을 줄 이기 위해 서 우 리 는 상술 한 상황 의 발생 을 피해 야 한다.

좋은 웹페이지 즐겨찾기