——————————————————————————————

有的时候理解平时习而为常的一件事情,到时有很多的意外的发现,今天就从一条MYSQL的查询语句入手,看看我们还能挖掘点什么?


首先一个SQL 语句,会经历二个阶段, 1 解析, 2 执行计划生成


select * from employees as e 

left join salaries as s on e.emp_no = s.emp_no 

where e.emp_no = '10009' order by s.to_date limit 1;


看似没有什么,来我们看一下解析后的这条语句的执行过程(想看的请移到文章末尾,太长了)


估计看到的都觉得,怎么这个处理的过程这么长。是的,就是我们平时不觉得的一条普通的语句,其实经理一个“漫长的”过程,在能提取结果。


那我们来一段段的看,到底发生了什么。并且可以让我们理解那些 “文章” 中告诉我们的SQL 语句执行的顺序到底对不对。


1 Join_preparation, 是的一条语句如果你要做JOIN 的操作,从内部SQL的解析来看,是这样的,他的第一步就是做 JOIN 

通过一条简单的SQL 来理解MYSQL的解析SQL的过程_字段

顺便说一句,那些写JOIN SQL的语句的 人er们,请别用*了,你看你写*是方便了,SQL 第一步就会将你的这些 * 解析为每个字段,用那个就写那个,并且标清楚你要访问那个表的字段,这样是对解析是很有好处的。

通过一条简单的SQL 来理解MYSQL的解析SQL的过程_sql_02


在做完了,transformations_to_nested_joins  后,我们看看语句又到了哪一步, where 条件,这里显示的是我们的where条件是一个等值的并且是固定的方式进行的查询, 这其中包含,等值优化,常量优化,细节条件排查


通过一条简单的SQL 来理解MYSQL的解析SQL的过程_字段_03


下面标志清楚JOIN 的字段之间的关联性, 并且很清楚的标志清楚依赖的两个表,并且也告知了 JOIN 的方式   NESTED_LOOP 的方式,从 employees 中选一条,与salaries 的所有记录进行一对一的比对。salaries 有 2835359 条记录,并且走的是 salaries  表的主键,(emp_no from_date)

通过一条简单的SQL 来理解MYSQL的解析SQL的过程_mysql_04


 下面就开始展示计划了,从下面的信息中,我们语句判断查询的方式走主键,并且走EQ 方式,不使用 MYSQL的 mrr (不知道什么是MRR 的可以百度一下)


通过一条简单的SQL 来理解MYSQL的解析SQL的过程_字段_05


rows 中显示过滤后的行数,以及cost。


选择访问的范围


通过一条简单的SQL 来理解MYSQL的解析SQL的过程_sql_06


ORDER BY 


通过一条简单的SQL 来理解MYSQL的解析SQL的过程_sql_07


而通过下面的截图我们可以看到,做一个join 要包含创建一个 tmp_table,位置在内存中,并且给这块的内存的行评估是要放置  1118481行数据

后面我们还有一个order by要处理,通过 filesort 的方式,升序,并且也使用刚才执行计划生成的内存  TMP_TABLE 


通过一条简单的SQL 来理解MYSQL的解析SQL的过程_mysql_08


以上的信息获得是通过 MYSQL  optimizer_trace 功能来获取的,具体的获取方式如下,(由于这样操作会消耗系统性能,强烈不建议默认开启,并且在生产系统上禁用,仅仅为分析问题使用)

打开优化trace

SET optimizer_trace="enabled=on"; 

查看获取记录

SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE; 

关闭trace 

SET optimizer_trace="enabled=off";




通过一条简单的SQL 来理解MYSQL的解析SQL的过程_字段_09


——————————————————————————


| select * from employees as e left join salaries as s on e.emp_no = s.emp_no where e.emp_no = '10009' order by s.to_date limit 1 | {

  "steps": [

    {

      "join_preparation": {

        "select#": 1,

        "steps": [

          {

            "expanded_query": "/* select#1 */ select `e`.`emp_no` AS `emp_no`,`e`.`birth_date` AS `birth_date`,`e`.`first_name` AS `first_name`,`e`.`last_name` AS `last_name`,`e`.`gender` AS `gender`,`e`.`hire_date` AS `hire_date`,`s`.`emp_no` AS `emp_no`,`s`.`salary` AS `salary`,`s`.`from_date` AS `from_date`,`s`.`to_date` AS `to_date` from (`employees` `e` left join `salaries` `s` on((`e`.`emp_no` = `s`.`emp_no`))) where (`e`.`emp_no` = '10009') order by `s`.`to_date` limit 1"

          },

          {

            "transformations_to_nested_joins": {

              "transformations": [

                "parenthesis_removal"

              ],

              "expanded_query": "/* select#1 */ select `e`.`emp_no` AS `emp_no`,`e`.`birth_date` AS `birth_date`,`e`.`first_name` AS `first_name`,`e`.`last_name` AS `last_name`,`e`.`gender` AS `gender`,`e`.`hire_date` AS `hire_date`,`s`.`emp_no` AS `emp_no`,`s`.`salary` AS `salary`,`s`.`from_date` AS `from_date`,`s`.`to_date` AS `to_date` from `employees` `e` left join `salaries` `s` on((`e`.`emp_no` = `s`.`emp_no`)) where (`e`.`emp_no` = '10009') order by `s`.`to_date` limit 1"

            }

          }

        ]

      }

    },

    {

      "join_optimization": {

        "select#": 1,

        "steps": [

          {

            "condition_processing": {

              "condition": "WHERE",

              "original_condition": "(`e`.`emp_no` = '10009')",

              "steps": [

                {

                  "transformation": "equality_propagation",

                  "resulting_condition": "(`e`.`emp_no` = '10009')"

                },

                {

                  "transformation": "constant_propagation",

                  "resulting_condition": "(`e`.`emp_no` = '10009')"

                },

                {

                  "transformation": "trivial_condition_removal",

                  "resulting_condition": "(`e`.`emp_no` = '10009')"

                }

              ]

            }

          },

          {

            "substitute_generated_columns": {

            }

          },

          {

            "table_dependencies": [

              {

                "table": "`employees` `e`",

                "row_may_be_null": false,

                "map_bit": 0,

                "depends_on_map_bits": [

                ]

              },

              {

                "table": "`salaries` `s`",

                "row_may_be_null": true,

                "map_bit": 1,

                "depends_on_map_bits": [

                  0

                ]

              }

            ]

          },

          {

            "ref_optimizer_key_uses": [

              {

                "table": "`employees` `e`",

                "field": "emp_no",

                "equals": "'10009'",

                "null_rejecting": false

              },

              {

                "table": "`salaries` `s`",

                "field": "emp_no",

                "equals": "`e`.`emp_no`",

                "null_rejecting": false

              }

            ]

          },

          {

            "rows_estimation": [

              {

                "table": "`employees` `e`",

                "rows": 1,

                "cost": 1,

                "table_type": "const",

                "empty": false

              },

              {

                "table": "`salaries` `s`",

                "range_analysis": {

                  "table_scan": {

                    "rows": 2835359,

                    "cost": 574517

                  },

                  "potential_range_indexes": [

                    {

                      "index": "PRIMARY",

                      "usable": true,

                      "key_parts": [

                        "emp_no",

                        "from_date"

                      ]

                    }

                  ],

                  "setup_range_conditions": [

                  ],

                  "group_index_range": {

                    "chosen": false,

                    "cause": "not_single_table"

                  },

                  "analyzing_range_alternatives": {

                    "range_scan_alternatives": [

                      {

                        "index": "PRIMARY",

                        "ranges": [

                          "10009 <= emp_no <= 10009"

                        ],

                        "index_dives_for_eq_ranges": true,

                        "rowid_ordered": true,

                        "using_mrr": false,

                        "index_only": false,

                        "rows": 18,

                        "cost": 4.6314,

                        "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": 18,

                      "ranges": [

                        "10009 <= emp_no <= 10009"

                      ]

                    },

                    "rows_for_plan": 18,

                    "cost_for_plan": 4.6314,

                    "chosen": true

                  }

                }

              }

            ]

          },

          {

            "considered_execution_plans": [

              {

                "plan_prefix": [

                  "`employees` `e`"

                ],

                "table": "`salaries` `s`",

                "best_access_path": {

                  "considered_access_paths": [

                    {

                      "access_type": "ref",

                      "index": "PRIMARY",

                      "rows": 18,

                      "cost": 4.6214,

                      "chosen": true

                    },

                    {

                      "access_type": "range",

                      "range_details": {

                        "used_index": "PRIMARY"

                      },

                      "chosen": false,

                      "cause": "heuristic_index_cheaper"

                    }

                  ]

                },

                "condition_filtering_pct": 100,

                "rows_for_plan": 18,

                "cost_for_plan": 4.6214,

                "chosen": true

              }

            ]

          },

          {

            "condition_on_constant_tables": "('10009' = '10009')",

            "condition_value": true

          },

          {

            "attaching_conditions_to_tables": {

              "original_condition": "('10009' = '10009')",

              "attached_conditions_computation": [

              ],

              "attached_conditions_summary": [

                {

                  "table": "`salaries` `s`",

                  "attached": null

                }

              ]

            }

          },

          {

            "clause_processing": {

              "clause": "ORDER BY",

              "original_clause": "`s`.`to_date`",

              "items": [

                {

                  "item": "`s`.`to_date`"

                }

              ],

              "resulting_clause_is_simple": false,

              "resulting_clause": "`s`.`to_date`"

            }

          },

          {

            "refine_plan": [

              {

                "table": "`salaries` `s`"

              }

            ]

          }

        ]

      }

    },

    {

      "join_execution": {

        "select#": 1,

        "steps": [

          {

            "creating_tmp_table": {

              "tmp_table_info": {

                "table": "intermediate_tmp_table",

                "row_length": 15,

                "key_length": 0,

                "unique_constraint": false,

                "location": "memory (heap)",

                "row_limit_estimate": 1118481

              }

            }

          },

          {

            "filesort_information": [

              {

                "direction": "asc",

                "table": "intermediate_tmp_table",

                "field": "to_date"

              }

            ],

            "filesort_priority_queue_optimization": {

              "limit": 1,

              "rows_estimate": 28,

              "row_size": 12,

              "memory_available": 8388608,

              "chosen": true

            },

            "filesort_execution": [

            ],

            "filesort_summary": {

              "rows": 2,

              "examined_rows": 18,

              "number_of_tmp_files": 0,

              "sort_buffer_size": 40,

              "sort_mode": "<sort_key, rowid>"

            }

          }

        ]

      }

    }

  ]

}