Mysql成本计算规则Optimizer trace

mysql原理--optimizer trace表的神器功效-CSDN博客

MySql5.6之前只能通过Explain语句查看到最后优化器决定使用的执行计划,却无法知道它们为什么做这个决策,在MySql5.6以及之后的版本mysql提出了Optimizer trace(优化跟踪)的功能,它可以让我们看到优化器生成执行计划的整个过程。

如果想打开这个功能,必须首先把 enabled 的值改为 on ,就像这样: `SET optimizer_trace="enabled=on"

然后我们就可以输入我们想要看优化查询过程的语句,当该语句执行完成后,就可以看到information_schema数据库下的optimizer_trace表中查看完整的优化过程。这个optimizer_trace表有4列,分别是。

  1. query:表示我们的查询语句
  2. tace表示优化过程的json文本
  3. missing_bytes_beyond_max_size:由于优化过程可能会输出很多,如果超过某个限时,多余的文本将会不显示,这个字段展示了被忽略的文本字节数
  4. insufficient_privileges:表示是否没有权限查看优化过程,默认值是0,止呕某些特殊情况下才会是1。

在我们有一个搜索条件比较多的查询语句,它的执行计划如下:EXPLAIN SELECT * FROM t1 WHERE key1 > 'z' AND key2 < 1000000 AND key3 IN ('a', 'b', 'c') AND common_field = 'abc';

可以看到该查询可能使用到的索引有3个,那么为什么优化器最终选择了 idx_key1 而不选择其他的索引或者直接全表扫描呢?这时候就可以通过 otpimzer trace 功能来查看优化器的具体工作过程:

  1. SET optimizer_trace="enabled=on";
  2. SELECT * FROM t1 WHERE key1 > 'z' AND key2 < 1000000 AND key3 IN ('a', 'b', 'c') AND common_field = 'abc';
  3. SELECT * FROM information_schema.OPTIMIZER_TRACEG
QUERY: SELECT * FROM t1 WHERE key1 > 'z' AND key2 < 1000000 AND key3 IN ('a', 'b', 'c') AND common_field = 'abc'
TRACE: {
    "steps": [
        {
            "join_preparation": {
                "select#": 1,
                "steps": [
                    {
                    "IN_uses_bisection": true
                    },
                    {
                    "expanded_query": "/* select#1 */ select `t1`.`id` AS `id`,`t1`.`key1` AS `key1`,`t1`.`key2` AS `key2`,`t1`.`key3` AS `key3`,`t1`.`key_part1` AS `key_part1`,`t1`.`key_part2` AS `key_part2`,`t1`.`key_part3` AS `key_part3`,`t1`.`common_field` AS `common_field` from `t1` where ((`t1`.`key1` > 'z') and (`t1`.`key2` < 1000000) and (`t1`.`key3` in ('a','b','c')) and (`t1`.`common_field` = 'abc'))"
                    }
                ]
            }
        },
        {
            "join_optimization": {
                "select#": 1,
                "steps": [
                    {
                        "condition_processing": {
                            "condition": "WHERE",
                            "original_condition": "((`t1`.`key1` > 'z') and (`t1`.`key2` < 1000000) and (`t1`.`key3` in ('a','b','c')) and (`t1`.`common_field` = 'abc'))",
                            "steps": [
                                {
                                "transformation": "equality_propagation",
                                "resulting_condition": "((`t1`.`key1` > 'z') and (`t1`.`key2` < 1000000) and (`t1`.`key3` in ('a','b','c')) and (`t1`.`common_field` = 'abc'))"
                                },
                                {
                                "transformation": "constant_propagation",
                                "resulting_condition": "((`t1`.`key1` > 'z') and (`t1`.`key2` < 1000000) and (`t1`.`key3` in ('a','b','c')) and (`t1`.`common_field` = 'abc'))"
                                },
                                {
                                "transformation": "trivial_condition_removal",
                                "resulting_condition": "((`t1`.`key1` > 'z') and (`t1`.`key2` < 1000000) and (`t1`.`key3` in ('a','b','c')) and (`t1`.`common_field` = 'abc'))"
                                }
                            ]
                        }
                    },
                    {
                        "substitute_generated_columns": {
                        }
                    },
                    {
                        "table_dependencies": [
                            {
                                "table": "`t1`",
                                "row_may_be_null": false,
                                "map_bit": 0,
                                "depends_on_map_bits": [
                                ]
                            }
                        ]
                    },
                    {
                        "ref_optimizer_key_uses": [
                        ]
                    },
                    {
                        "rows_estimation": [
                            {
                                "table": "`t1`",
                                "range_analysis": {
                                    "table_scan": {
                                        "rows": 3,
                                        "cost": 2.65
                                    },
                                    "potential_range_indexes": [
                                        {
                                            "index": "PRIMARY",
                                            "usable": false,
                                            "cause": "not_applicable"
                                        },
                                        {
                                            "index": "idx_key2",
                                            "usable": true,
                                            "key_parts": [
                                                "key2"
                                            ]
                                        },
                                        {
                                            "index": "idx_key1",
                                            "usable": true,
                                            "key_parts": [
                                                "key1",
                                                "id"
                                            ]
                                        },
                                        {
                                            "index": "idx_key3",
                                            "usable": true,
                                            "key_parts": [
                                                "key3",
                                                "id"
                                            ]
                                        },
                                        {
                                            "index": "idx_key_part",
                                            "usable": false,
                                            "cause": "not_applicable"
                                        }
                                    ],
                                    "setup_range_conditions": [
                                    ],
                                    "group_index_range": {
                                        "chosen": false,
                                        "cause": "not_group_by_or_distinct"
                                    },
                                    "skip_scan_range": {
                                        "potential_skip_scan_indexes": [
                                            {
                                                "index": "idx_key2",
                                                "usable": false,
                                                "cause": "query_references_nonkey_column"
                                            },
                                            {
                                                "index": "idx_key1",
                                                "usable": false,
                                                "cause": "query_references_nonkey_column"
                                            },
                                            {
                                                "index": "idx_key3",
                                                "usable": false,
                                                "cause": "query_references_nonkey_column"
                                            }
                                        ]
                                    },
                                    "analyzing_range_alternatives": {
                                        "range_scan_alternatives": [
                                            {
                                                "index": "idx_key2",
                                                "ranges": [
                                                    "NULL < key2 < 1000000"
                                                ],
                                                "index_dives_for_eq_ranges": true,
                                                "rowid_ordered": false,
                                                "using_mrr": false,
                                                "index_only": false,
                                                "in_memory": 1,
                                                "rows": 3,
                                                "cost": 1.31,
                                                "chosen": true
                                            },
                                            {
                                                "index": "idx_key1",
                                                "ranges": [
                                                    "'z' < key1"
                                                ],
                                                "index_dives_for_eq_ranges": true,
                                                "rowid_ordered": false,
                                                "using_mrr": false,
                                                "index_only": false,
                                                "in_memory": 1,
                                                "rows": 1,
                                                "cost": 0.61,
                                                "chosen": true
                                            },
                                            {
                                                "index": "idx_key3",
                                                "ranges": [
                                                    "key3 = 'a'",
                                                    "key3 = 'b'",
                                                    "key3 = 'c'"
                                                ],
                                                "index_dives_for_eq_ranges": true,
                                                "rowid_ordered": false,
                                                "using_mrr": false,
                                                "index_only": false,
                                                "in_memory": 1,
                                                "rows": 3,
                                                "cost": 1.81,
                                                "chosen": false,
                                                "cause": "cost"
                                            }
                                        ],
                                        "analyzing_roworder_intersect": {
                                            "usable": false,
                                            "cause": "too_few_roworder_scans"
                                        }
                                    },
                                    "chosen_range_access_summary": {
                                        "range_access_plan": {
                                            "type": "range_scan",
                                            "index": "idx_key1",
                                            "rows": 1,
                                            "ranges": [
                                                "'z' < key1"
                                            ]
                                        },
                                        "rows_for_plan": 1,
                                        "cost_for_plan": 0.61,
                                        "chosen": true
                                    }
                                }
                            }
                        ]
                    },
                    {
                        "considered_execution_plans": [
                            {
                                "plan_prefix": [
                                ],
                                "table": "`t1`",
                                "best_access_path": {
                                    "considered_access_paths": [
                                        {
                                            "rows_to_scan": 1,
                                            "access_type": "range",
                                            "range_details": {
                                                "used_index": "idx_key1"
                                            },
                                            "resulting_rows": 1,
                                            "cost": 0.71,
                                            "chosen": true
                                        }
                                    ]
                                },
                                "condition_filtering_pct": 100,
                                "rows_for_plan": 1,
                                "cost_for_plan": 0.71,
                                "chosen": true
                            }
                        ]
                    },
                    {
                        "attaching_conditions_to_tables": {
                            "original_condition": "((`t1`.`key1` > 'z') and (`t1`.`key2` < 1000000) and (`t1`.`key3` in ('a','b','c')) and (`t1`.`common_field` = 'abc'))",
                            "attached_conditions_computation": [
                            ],
                            "attached_conditions_summary": [
                                {
                                    "table": "`t1`",
                                    "attached": "((`t1`.`key1` > 'z') and (`t1`.`key2` < 1000000) and (`t1`.`key3` in ('a','b','c')) and (`t1`.`common_field` = 'abc'))"
                                }
                            ]
                        }
                    },
                    {
                        "finalizing_table_conditions": [
                            {
                                "table": "`t1`",
                                "original_table_condition": "((`t1`.`key1` > 'z') and (`t1`.`key2` < 1000000) and (`t1`.`key3` in ('a','b','c')) and (`t1`.`common_field` = 'abc'))",
                                "final_table_condition   ": "((`t1`.`key1` > 'z') and (`t1`.`key2` < 1000000) and (`t1`.`key3` in ('a','b','c')) and (`t1`.`common_field` = 'abc'))"
                            }
                        ]
                    },
                    {
                        "refine_plan": [
                            {
                                "table": "`t1`",
                                "pushed_index_condition": "(`t1`.`key1` > 'z')",
                                "table_condition_attached": "((`t1`.`key2` < 1000000) and (`t1`.`key3` in ('a','b','c')) and (`t1`.`common_field` = 'abc'))"
                            }
                        ]
                    }
                ]
            }
        },
        {
            "join_execution": {
                "select#": 1,
                "steps": [
                ]
            }
        }
    ]
}
MISSING_BYTES_BEYOND_MAX_MEM_SIZE: 0
INSUFFICIENT_PRIVILEGES: 0

优化过程大致分为了三个阶段

  1. prepare准备阶段
  2. optimize优化阶段
  3. execute执行阶段

我们所说的基于成本的优化主要集中在 optimize 阶段,对于单表查询来说,我们主要关注 optimize 阶段的 “rows_estimation” 这个过程,这个过程深入分析了对单表查询的各种执行方案的成本;对于多表连接查询来说,我们更多需要关注 “considered_execution_plans” 这个过程,这个过程里会写明各种不同的连接方式所对应的成本。反正优化器最终会选择成本最低的那种方案来作为最终的执行计划,也就是我们使用 EXPLAIN 语句所展现出的那种方案。如果有小伙伴对使用 EXPLAIN 语句展示出的对某个查询的执行计划很不理解,大家可以尝试使用 optimizer trace 功能来详细了解每一种执行方案对应的成本,相信这个功能能让大家更深入的了解 MySQL 查询优化器。

Last modification:April 23, 2024
如果觉得我的文章对你有用,请随意赞赏