옵티마이저의 판단을 알기 위한 방법으로 explain 명령어를 사용한다. 하지만 explain 옵티마이저가 최종적으로 선택한 실행 계획 뿐이고, 과정에 최적화나 비용 계산, 또는 실행 계획의 비교가 어떻게 일어 났는지는 없다. 옵티마이저 트레이스에는 이러한 내용이 설명 되어있다.

mysql> explain select * from t1 join t3 on (t1.c1=t3.pk and t3.pk < 113);
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra                                              |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+----------------------------------------------------+
|  1 | SIMPLE      | t3    | NULL       | range | PRIMARY       | PRIMARY | 4       | NULL |    2 |   100.00 | Using where                                        |
|  1 | SIMPLE      | t1    | NULL       | ALL   | NULL          | NULL    | NULL    | NULL |   10 |    10.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+----------------------------------------------------+
2 rows in set, 1 warning (0.00 sec)


옵티마이저
트레이스의 사용법은 간단하다.

  1. 옵티마이저 트레이스를 활성화한다.
  2. 해석하고 싶은 쿼리를 실행한다.
  3. 트레이스를 출력한다.

 

SQL을 수행하면 아래 그림처럼 진행이 되는데, 옵티마이저 트레이스를 출력하면 옵티마이저가 하는 역할을 그대로 확인 할 수 있다.

 

실행 계획은 information_schema에서 json 형식으로 있다.

select * from inforamtion_schema.optimizer_trace\G;

 

옵티마이저 트레이스를 제어하는 시스템 변수를 확인 하자.

세션 변수이므로 그냥 변경하면 현재 세션에만 적용 된다.

- 옵티마이저 트레이스의 활성화/ 비활성화

set optimizer_trace='enabled=on';
set optimizer_trace='enabled=off';

- 옵티마이저 트레이스 최대 저장 갯수 변경

SET optimizer_trace_offset=-2, optimizer_trace_limit=5; << 마지막 2개 수생된거 부터 5개 저장
SET optimizer_trace_offset=0, optimizer_trace_limit=5; << 마지막 수행된거 부터 5개 저장 (추천, limit 값만 조절 할 것)

※ 최대 출력 갯수는 optimizer_trace_max_mem_size 의 영향을 받는다.

- 옵티마이저 트레이스 다중 출력

select * from information_schema.optimizer_trace ; << 순서대로 모두 출럭 (추천)
select * from information_schema.optimizer_trace limit 1 ; << 1번째 1개 출력
select * from information_schema.optimizer_trace limit 1 offset 1 ; << 2번째 1개 출력
select * from information_schema.optimizer_trace limit 2 offset 0 ; << 1번째 부터 2개 출력
select * from information_schema.optimizer_trace limit 2 offset 1 ; << 2번째 부터 2개 출력
select * from information_schema.optimizer_trace limit 2 offset 2 ; << 3번째 부터 2개 출럭

 

쿼리를 수행하고 트레이스를 확인 보았다.

출력되는 결과가 너무 길어서 잘라서 보자.

mysql> select * from information_schema.optimizer_trace\G;
*************************** 1. row ***************************
                            QUERY: select * from t1 join t3 on (t1.c1=t3.pk and t3.pk < 113)
                            TRACE: {
  "steps": [
    {
      "join_preparation": {
        "select#": 1,
        "steps": [
          {
            "expanded_query": "/* select#1 */ select `t1`.`c1` AS `c1`,`t1`.`c2` AS `c2`,`t3`.`pk` AS `pk`,`t3`.`i` AS `i` from (`t1` join `t3` on(((`t1`.`c1` = `t3`.`pk`) and (`t3`.`pk` < 113))))"
          },
          {
            "transformations_to_nested_joins": {
              "transformations": [
                "JOIN_condition_to_WHERE",
                "parenthesis_removal"
              ],
              "expanded_query": "/* select#1 */ select `t1`.`c1` AS `c1`,`t1`.`c2` AS `c2`,`t3`.`pk` AS `pk`,`t3`.`i` AS `i` from `t1` join `t3` where ((`t1`.`c1` = `t3`.`pk`) and (`t3`.`pk` < 113))"
            }
          }
        ]
      }
    },

QUERY 컬럼을 통해 실제 입력된 쿼리를 있다.

join_preparation select# explain id 동일한 값이다.

join_preparation transformations_to_nested_joins 에서 쿼리의 실행 계획을 찾기 전에 쿼리를 완전한 형태로 열어 조인문의 on 절에 있는 조건을 where 절로 이동 시킨다.

 

        {
      "join_optimization": {
        "select#": 1,
        "steps": [
          {
            "condition_processing": {
              "condition": "WHERE",
              "original_condition": "((`t1`.`c1` = `t3`.`pk`) and (`t3`.`pk` < 113))",
              "steps": [
                {
                  "transformation": "equality_propagation",
                  "resulting_condition": "((`t3`.`pk` < 113) and multiple equal(`t1`.`c1`, `t3`.`pk`))"
                },
                {
                  "transformation": "constant_propagation",
                  "resulting_condition": "((`t3`.`pk` < 113) and multiple equal(`t1`.`c1`, `t3`.`pk`))"
                },
                {
                  "transformation": "trivial_condition_removal",
                  "resulting_condition": "((`t3`.`pk` < 113) and multiple equal(`t1`.`c1`, `t3`.`pk`))"
                }
              ]
            }
          },

join_optimization 처음 단계는 where 절의 변환이다.원래 on 절에 지정되어 있던 것들 불필요한 조건을 제거한 옵티마이저가 해석하기 쉬운 형태로 변경 한다. 3개의 변환 알고리즘이 적용 되었다.

equality_propagation(등가 비교에 의한 추이율) 적용한 결과 c1, pk 컬럼이 같은 값이라고 판단하여 같은 그룹(multiple equal)으로 합쳐졌다.

constant_propagation(정수의 등가 비교에 의한 추이) trivial_condition_removal(자명한 조건의 삭제) 조건이 포함 되지 않아 변환은 일어나지 않았다. trivial_condition_removal에서는 만일 where...and 1=1 같은 불필요한 조건이 포함되어 있을 경우 삭제 된다.

위의 과정을 좀 자세히 보면 다음과 같다.

 

           {
            "substitute_generated_columns": {
            }
          },
          {
            "table_dependencies": [
              {
                "table": "`t1`",
                "row_may_be_null": false,
                "map_bit": 0,
                "depends_on_map_bits": [
                ]
              },
              {
                "table": "`t3`",
                "row_may_be_null": false,
                "map_bit": 1,
                "depends_on_map_bits": [
                ]
              }
            ]
          },
          {
            "ref_optimizer_key_uses": [
              {
                "table": "`t3`",
                "field": "pk",
                "equals": "`t1`.`c1`",
                "null_rejecting": true
              }
            ]
          },
          {
            "rows_estimation": [
              {
                "table": "`t1`",
                "table_scan": {
                  "rows": 10,
                  "cost": 0.25
                }
              },
              {
                "table": "`t3`",
                "range_analysis": {
                  "table_scan": {
                    "rows": 4,
                    "cost": 2.75
                  },
                  "potential_range_indexes": [
                    {
                      "index": "PRIMARY",
                      "usable": true,
                      "key_parts": [
                        "pk"
                      ]
                    }
                  ],
                  "setup_range_conditions": [
                  ],
                  "group_index_range": {
                    "chosen": false,
                    "cause": "not_single_table"
                  },
                  "skip_scan_range": {
                    "chosen": false,
                    "cause": "not_single_table"
                  },
                  "analyzing_range_alternatives": {
                    "range_scan_alternatives": [
                      {
                        "index": "PRIMARY",
                        "ranges": [
                          "pk < 113"
                        ],
                        "index_dives_for_eq_ranges": true,
                        "rowid_ordered": true,
                        "using_mrr": false,
                        "index_only": false,
                        "rows": 2,
                        "cost": 0.71,
                        "chosen": true
                      }
                    ],
                    "analyzing_roworder_intersect": {
                      "usable": false,
                      "cause": "too_few_roworder_scans"
                    }
                  },
                  "chosen_range_access_summary": {
                    "range_access_plan": {
                      "type": "range_scan",
                      "index": "PRIMARY",
                      "rows": 2,
                      "ranges": [
                        "pk < 113"
                      ]
                    },
                    "rows_for_plan": 2,
                    "cost_for_plan": 0.71,
                    "chosen": true
                  }
                }
              }
            ]
          },

substitute_generated_columns은 컬럼 처리 방식으로 table_dependencies에는 테이블의 의존 관계가 나타나 있다. 이는 outer join에서 의미가 있는 항목이다. outer join에는 depends_on_map_bits에 의존하는 테이블의 map_bit가 표시된다.

ref_optimizer_key_uses에는 이쿼리에서 이용 가능한 인덱스이 목록이 나열된다.

rows_estimation에는 접근한 테이블의 수가 출력된다. 또한 테이블 스캔을 실행할 때의 비용을 있다.

 

          {
            "considered_execution_plans": [
              {
                "plan_prefix": [
                ],
                "table": "`t1`",
                "best_access_path": {
                  "considered_access_paths": [
                    {
                      "rows_to_scan": 10,
                      "filtering_effect": [
                      ],
                      "final_filtering_effect": 1,
                      "access_type": "scan",
                      "resulting_rows": 10,
                      "cost": 1.25,
                      "chosen": true
                    }
                  ]
                },
                "condition_filtering_pct": 100,
                "rows_for_plan": 10,
                "cost_for_plan": 1.25,
                "rest_of_plan": [
                  {
                    "plan_prefix": [
                      "`t1`"
                    ],
                    "table": "`t3`",
                    "best_access_path": {
                      "considered_access_paths": [
                        {
                          "access_type": "eq_ref",
                          "index": "PRIMARY",
                          "rows": 1,
                          "cost": 3.5,
                          "chosen": true,
                          "cause": "clustered_pk_chosen_by_heuristics"
                        },
                        {
                          "access_type": "range",
                          "range_details": {
                            "used_index": "PRIMARY"
                          },
                          "chosen": false,
                          "cause": "heuristic_index_cheaper"
                        }
                      ]
                    },
                    "condition_filtering_pct": 100,
                    "rows_for_plan": 10,
                    "cost_for_plan": 4.75,
                    "chosen": true
                  }
                ]
              },
              {
                "plan_prefix": [
                ],
                "table": "`t3`",
                "best_access_path": {
                  "considered_access_paths": [
                    {
                      "access_type": "ref",
                      "index": "PRIMARY",
                      "usable": false,
                      "chosen": false
                    },
                    {
                      "rows_to_scan": 2,
                      "filtering_effect": [
                      ],
                      "final_filtering_effect": 1,
                      "access_type": "range",
                      "range_details": {
                        "used_index": "PRIMARY"
                      },
                      "resulting_rows": 2,
                      "cost": 0.91,
                      "chosen": true
                    }
                  ]
                },
                "condition_filtering_pct": 100,
                "rows_for_plan": 2,
                "cost_for_plan": 0.91,
                "rest_of_plan": [
                  {
                    "plan_prefix": [
                      "`t3`"
                    ],
                    "table": "`t1`",
                    "best_access_path": {
                      "considered_access_paths": [
                        {
                          "rows_to_scan": 10,
                          "filtering_effect": [
                          ],
                          "final_filtering_effect": 1,
                          "access_type": "scan",
                          "using_join_cache": true,
                          "buffers_needed": 1,
                          "resulting_rows": 10,
                          "cost": 2.25,
                          "chosen": true
                        }
                      ]
                    },
                    "condition_filtering_pct": 100,
                    "rows_for_plan": 20,
                    "cost_for_plan": 3.16,
                    "chosen": true
                  }
                ]
              }
            ]
          },

considered_execution_plans 옵티마이저가 검토한 실행 계획을 배열로 표시한다.

plan_prefix는 지금까지 접근한 테이블을 나타낸다. 처음에 접근하는 테이블의 plan_prefix는 당연히 비어있다.

table 맴버는 현재 검토하고 있는 테이블을 가리킨다.

best_access_path는 가장 효율적인 접근 방식을 착기 위해 어떤 접근 방식을 검토했는가를 표시하고, 검토한 접근 방식은 considered_access_paths에 정리 되어 있다. 선택된 것은 chosen 맴버가 true 것으로 있다.

condition_filtering_pct는 테이블에서 데이터를 패치한 이후에 적용된 where 절의 조건으로 어느 정도 행의 범위 축소가 일어났는지를 예상한다. 여기서는 100% 되어 있기 대문에 범위 축소가 전혀 일어나지 않았다.

rest_of_plan은 이후의 테이블 접근 정보가 저장된다. 여기서는 조인한 경우를 있다.

두 개의 실행계획을 색으로 분리 하였다. t1->t3 조인 방법은 cost 4.75, t3->t1 조인 방법은 cost 3.16 이 소모된다.

 

          {
            "attaching_conditions_to_tables": {
              "original_condition": "((`t1`.`c1` = `t3`.`pk`) and (`t3`.`pk` < 113))",
              "attached_conditions_computation": [
              ],
              "attached_conditions_summary": [
                {
                  "table": "`t3`",
                  "attached": "(`t3`.`pk` < 113)"
                },
                {
                  "table": "`t1`",
                  "attached": "(`t1`.`c1` = `t3`.`pk`)"
                }
              ]
            }
          },
          {
            "finalizing_table_conditions": [
              {
                "table": "`t3`",
                "original_table_condition": "(`t3`.`pk` < 113)",
                "final_table_condition   ": "(`t3`.`pk` < 113)"
              },
              {
                "table": "`t1`",
                "original_table_condition": "(`t1`.`c1` = `t3`.`pk`)",
                "final_table_condition   ": "(`t1`.`c1` = `t3`.`pk`)"
              }
            ]
          },

attaching_conditions_to_tables는 추가로 적용될 where 절의 검색 조건을 정리한다.

 

            "refine_plan": [
              {
                "table": "`t3`"
              },
              {
                "table": "`t1`"
              }
            ]
          }
        ]
      }
    },
    {
      "join_execution": {
        "select#": 1,
        "steps": [
        ]
      }
    }
  ]
}
MISSING_BYTES_BEYOND_MAX_MEM_SIZE: 0
          INSUFFICIENT_PRIVILEGES: 0
1 rows in set (0.00 sec)

refine_plan은 join_optimization 마지막 항목이다. 단순히 어떤 테이블에 접근 했는지를 나타낸다.

MISSING_BYTES_BEYOND_MAX_MEM_SIZE는 옵티마이저 트레이스를 잘라낸 부분을 표시한다. 0이므로 잘라낸 부분이 없다. 만일 메모리가 부족하여 일부를 잘라내게 되면 이곳에 바이트를 잘라냈는지 표시한다. 메모리의 크기는 optimizer_trace_max_mem_size 지정한다. 기본값은 16KB (8.0.18 기준 1MB)이다.

 

출처 : https://dev.mysql.com/doc/refman/8.0/en/explain.html

 

MySQL :: MySQL 8.0 Reference Manual :: 13.8.2 EXPLAIN Syntax

{EXPLAIN | DESCRIBE | DESC} tbl_name [col_name | wild] {EXPLAIN | DESCRIBE | DESC} [explain_type] {explainable_stmt | FOR CONNECTION connection_id} {EXPLAIN | DESCRIBE | DESC} ANALYZE select_statement explain_type: { FORMAT = format_name } format_name: { T

dev.mysql.com

MySQL 8.0.18에서는 EXPLAIN ANALYZE 쿼리를 실행하면 옵티마이저의 기대치가 실제 실행과 어떻게 일치 하는지에 대한 타이밍 및 추가 iterator-based 정보와 함께 쿼리를 실행하고 출력을 생성 합니다.
다음 정보가 제공됩니다.

- Estimated execution cost
- Estimated number of returned rows
- Time to return first row
- Time to return all rows (actual cost)
- Number of rows returned by the iterator
- Number of loops


조회 실행 정보는 TREE 노드가 반복자를 나타내는 출력 형식을 사용하여 표시됩니다 . 
EXPLAIN ANALYZE 항상 TREE 출력 형식을 사용하고 형식 지정자를 허용하지 않습니다. 
FOR CONNECTION 과 함께 사용할 수도 없습니다.

EXPLAIN ANALYZE 는 SELECT 명령문 만 사용할 수 있습니다 .

출력 예 :

mysql> EXPLAIN ANALYZE SELECT * FROM t1 JOIN t2 ON (t1.c1 = t2.c2)\G
*************************** 1. row ***************************
EXPLAIN: -> Inner hash join (t2.c2 = t1.c1)  (cost=4.70 rows=6) 
(actual time=0.032..0.035 rows=6 loops=1)
    -> Table scan on t2  (cost=0.06 rows=6) 
(actual time=0.003..0.005 rows=6 loops=1)
    -> Hash
        -> Table scan on t1  (cost=0.85 rows=6) 
(actual time=0.018..0.022 rows=6 loops=1)

mysql> EXPLAIN ANALYZE SELECT * FROM t3 WHERE i > 8\G
*************************** 1. row ***************************
EXPLAIN: -> Filter: (t3.i > 8)  (cost=1.75 rows=5) 
(actual time=0.019..0.021 rows=6 loops=1)
    -> Table scan on t3  (cost=1.75 rows=15) 
(actual time=0.017..0.019 rows=15 loops=1)

mysql> EXPLAIN ANALYZE SELECT * FROM t3 WHERE pk > 17\G
*************************** 1. row ***************************
EXPLAIN: -> Filter: (t3.pk > 17)  (cost=1.26 rows=5) 
(actual time=0.013..0.016 rows=5 loops=1)
    -> Index range scan on t3 using PRIMARY  (cost=1.26 rows=5) 
(actual time=0.012..0.014 rows=5 loops=1)


예제 출력에 사용 된 테이블은 다음에 표시된 명령문으로 작성되었습니다.

CREATE TABLE t1 (
    c1 INT(11) DEFAULT NULL,
    c2 INT(11) DEFAULT NULL
);

CREATE TABLE t2 (
    c1 INT(11) DEFAULT NULL,
    c2 INT(11) DEFAULT NULL
);

CREATE TABLE t3 (
    pk INT(11) NOT NULL PRIMARY KEY,
    i INT(11) DEFAULT NULL
);

 

출처 : https://dev.mysql.com/doc/refman/8.0/en/hash-joins.html

 

MySQL :: MySQL 8.0 Reference Manual :: 8.2.1.4 Hash Join Optimization

8.2.1.4 Hash Join Optimization Beginning with MySQL 8.0.18, MySQL employs a hash join for any query for which each join has an equi-join condition and uses no indexes, such as this one: SELECT * FROM t1 JOIN t2 ON t1.c1=t2.c1; A hash join is usually faster

dev.mysql.com

 

MySQL 8.0.18 부터 MySQL은 각 조인이 동일 조인 조건을 가지며 인덱스를 사용하지 않는 모든 쿼리에 해시 조인을 사용합니다.

SELECT * 
    FROM t1 
    JOIN t2 
        ON t1.c1=t2.c1;


해시 조인은 일반적으로 빠르며 이전 버전의 MySQL에서 사용 된 block nested loop 알고리즘 대신 사용됩니다.

CREATE TABLE t1 (c1 INT, c2 INT);
CREATE TABLE t2 (c1 INT, c2 INT);
CREATE TABLE t3 (c1 INT, c2 INT);


다음 EXPLAIN FORMAT=TREE과 같이 사용하여 해시 조인이 사용되고 있음을 알 수 있습니다 .

mysql> EXPLAIN FORMAT=TREE
    -> SELECT * 
    ->     FROM t1 
    ->     JOIN t2 
    ->         ON t1.c1=t2.c1\G
*************************** 1. row ***************************
EXPLAIN: -> Inner hash join (t2.c1 = t1.c1)  (cost=0.70 rows=1)
    -> Table scan on t2  (cost=0.35 rows=1)
    -> Hash
        -> Table scan on t1  (cost=0.35 rows=1)


주어진 조인에 해시 조인이 사용되고 있는지 확인하려면 옵션 EXPLAIN과 함께 사용해야합니다 FORMAT=TREE. EXPLAIN ANALYZE 사용하면 해시 조인에 대한 정보도 표시합니다.

해시 조인은 각 테이블 쌍에 대해 하나 이상의 조인 조건이 여기에 표시된 쿼리와 같은 동일 조인 인 경우 여러 조인과 관련된 쿼리에도 사용됩니다.

SELECT * 
    FROM t1
    JOIN t2 
        ON (t1.c1 = t2.c1 AND t1.c2 < t2.c2)
    JOIN t3 
        ON (t2.c1 = t3.c1);


방금 표시된 것과 같은 경우 조인이 실행 된 후 동일 조인이 아닌 추가 조건이 필터로 적용됩니다. 

mysql> EXPLAIN FORMAT=TREE
    -> SELECT * 
    ->     FROM t1
    ->     JOIN t2 
    ->         ON (t1.c1 = t2.c1 AND t1.c2 < t2.c2)
    ->     JOIN t3 
    ->         ON (t2.c1 = t3.c1)\G
*************************** 1. row ***************************
EXPLAIN: -> Inner hash join (t3.c1 = t1.c1)  (cost=1.05 rows=1)
    -> Table scan on t3  (cost=0.35 rows=1)
    -> Hash
        -> Filter: (t1.c2 < t2.c2)  (cost=0.70 rows=1)
            -> Inner hash join (t2.c1 = t1.c1)  (cost=0.70 rows=1)
                -> Table scan on t2  (cost=0.35 rows=1)
                -> Hash
                    -> Table scan on t1  (cost=0.35 rows=1)


방금 표시된 출력에서 ​​볼 수 있듯이 여러 해시 조인은 여러 등일 조인 조건을 가진 조인에 사용될 수 있습니다.


조인 테이블과 동일 조인 조건이 쌍을 이룰 수 없는 경우 해시 조인을 사용할 수 없습니다.

mysql> EXPLAIN FORMAT=TREE
    ->     SELECT * 
    ->         FROM t1
    ->         JOIN t2 
    ->             ON (t1.c1 = t2.c1)
    ->         JOIN t3 
    ->             ON (t2.c1 < t3.c1)\G
*************************** 1. row ***************************
EXPLAIN: not executable by iterator executor


이 경우 인덱스를 사용할 수없는 MySQL 8.0.18 이전 버전에서와 같이 느린 블록 중첩 루프 알고리즘이 사용됩니다.

mysql> EXPLAIN
    ->     SELECT * 
    ->         FROM t1
    ->         JOIN t2 
    ->             ON (t1.c1 = t2.c1)
    ->         JOIN t3 
    ->             ON (t2.c1 < t3.c1)\G             
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1
     filtered: 100.00
        Extra: NULL
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: t2
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1
     filtered: 100.00
        Extra: Using where; Using join buffer (Block Nested Loop)
*************************** 3. row ***************************
           id: 1
  select_type: SIMPLE
        table: t3
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1
     filtered: 100.00
        Extra: Using where; Using join buffer (Block Nested Loop)


해시 조인은 Cartesian product에도 적용됩니다.

mysql> EXPLAIN FORMAT=TREE
    -> SELECT *
    ->     FROM t1
    ->     JOIN t2
    ->     WHERE t1.c2 > 50\G
*************************** 1. row ***************************
EXPLAIN: -> Inner hash join  (cost=0.70 rows=1)
    -> Table scan on t2  (cost=0.35 rows=1)
    -> Hash
        -> Filter: (t1.c2 > 50)  (cost=0.35 rows=1)
            -> Table scan on t1  (cost=0.35 rows=1)


기본적으로 MySQL은 가능할 때마다 해시 조인을 사용합니다. 해시 조인을 두 가지 방법 중 하나로 사용할지 여부를 제어 할 수 있습니다.

optimizer_switch 서버 시스템 변수를 global or session level에서 hash_join=on또는 hash_join=off에 대한 설정을 변경 합니다. 
기본값은 hash_join=on입니다.

경우에 따라 옵티마이저 파라미터를 사용 하거나 HASH_JOIN, NO_HASH_JOIN 힌트를 사용합니다.

해시 조인에 의한 메모리 사용량은 join_buffer_size 시스템 변수를 사용하여 제어 할 수 있습니다 . 
해시 조인은 join_buffer_size 보다 많은 메모리를 사용할 수 없습니다. 
해시 조인에 필요한 메모리가 사용 가능한 양을 초과하면 MySQL은 디스크의 파일을 사용하여 이를 처리합니다. 
이 경우 해시 조인이 open_files_limit에 설정된 것보다 많은 파일을 만들면 조인에 실패 할 수 있습니다. 

'MySQL' 카테고리의 다른 글

optimizer trace  (0) 2019.11.26
MySQL EXPLAIN ANALYZE  (0) 2019.10.02
MySQL 시퀀스(AUTO_INCREMENT) 조회 및 초기화  (0) 2018.09.18
Specified key was too long (부제: mysql 인덱스 생성 힘드네)  (0) 2017.06.09
MySQL 설치 (5.6 or 5.7)  (0) 2017.03.09

int(11) auto increment 최대 4294967295 이후에는 error

unsigned BIGINT 최대 18446744073709551615 까지 사용 가능 



-- 테이블의 상태 확인

show table status where name='T_HADOOP_LATEST_METRICS';

+-------------------------+--------+---------+------------+-------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-----------------+----------+----------------+---------+

| Name                    | Engine | Version | Row_format | Rows  | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time         | Update_time | Check_time | Collation       | Checksum | Create_options | Comment |

+-------------------------+--------+---------+------------+-------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-----------------+----------+----------------+---------+

| T_HADOOP_LATEST_METRICS | InnoDB |      10 | Compact    | 18124 |            144 |     2621440 |               0 |      7913472 |   4194304 |     4294967295 | 2017-11-06 13:57:16 | NULL        | NULL       | utf8_general_ci |     NULL |                |         |

+-------------------------+--------+---------+------------+-------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-----------------+----------+----------------+---------+

1 row in set (0.00 sec)



-- 시퀀스 조회 (20억 이상)

SELECT table_name,table_comment,table_schema,table_type,engine,

version,row_format,table_rows,avg_row_length,data_length,

max_data_length,index_length,AUTO_INCREMENT,create_time,table_collation,

CEILING((data_length+index_length)/1024/1024) AS total_mb,

CEILING((data_length)/1024/1024) AS data_mb,

CEILING((index_length)/1024/1024) AS index_mb

FROM information_schema.tables 

WHERE table_schema='cloumon'

and Auto_increment > 2000000000

ORDER BY Auto_increment DESC

;


+-------------------------+---------------+--------------+------------+--------+---------+------------+------------+----------------+-------------+-----------------+--------------+----------------+---------------------+-----------------+----------+---------+----------+

| table_name              | table_comment | table_schema | table_type | engine | version | row_format | table_rows | avg_row_length | data_length | max_data_length | index_length | AUTO_INCREMENT | create_time         | table_collation | total_mb | data_mb | index_mb |

+-------------------------+---------------+--------------+------------+--------+---------+------------+------------+----------------+-------------+-----------------+--------------+----------------+---------------------+-----------------+----------+---------+----------+

| T_HADOOP_LATEST_METRICS |               | cloumon      | BASE TABLE | InnoDB |      10 | Compact    |      18628 |            140 |     2621440 |               0 |      7913472 |     4294967295 | 2017-11-06 13:57:16 | utf8_general_ci |       11 |       3 |        8 |

| T_HOST_LATEST_METRICS   |               | cloumon      | BASE TABLE | InnoDB |      10 | Compact    |      17253 |             92 |     1589248 |               0 |      3178496 |     4294967295 | 2017-11-06 13:57:18 | utf8_general_ci |        5 |       2 |        4 |

| T_HBASE_LATEST_METRICS  |               | cloumon      | BASE TABLE | InnoDB |      10 | Compact    |      14489 |            182 |     2637824 |               0 |      8454144 |     4142014594 | 2017-11-06 13:57:17 | utf8_general_ci |       11 |       3 |        9 |

| T_MR_LATEST_METRICS     |               | cloumon      | BASE TABLE | InnoDB |      10 | Compact    |       3402 |            105 |      360448 |               0 |      1081344 |     2501997189 | 2017-11-06 13:57:20 | utf8_general_ci |        2 |       1 |        2 |

+-------------------------+---------------+--------------+------------+--------+---------+------------+------------+----------------+-------------+-----------------+--------------+----------------+---------------------+-----------------+----------+---------+----------+

4 rows in set (2.59 sec)



-- 시퀀스 초기화

use cloumon;

alter table T_HADOOP_LATEST_METRICS auto_increment=1;

alter table T_HOST_LATEST_METRICS auto_increment=1;

alter table T_HBASE_LATEST_METRICS auto_increment=1;

alter table T_MR_LATEST_METRICS auto_increment=1;

'MySQL' 카테고리의 다른 글

MySQL EXPLAIN ANALYZE  (0) 2019.10.02
MySQL Hash Join Optimization  (0) 2019.10.02
Specified key was too long (부제: mysql 인덱스 생성 힘드네)  (0) 2017.06.09
MySQL 설치 (5.6 or 5.7)  (0) 2017.03.09
MySQL load data  (0) 2016.10.27

+ Recent posts