MySQL如何选择合适的索引

先来看一个栗子

EXPLAIN select * from employees where name > 'a';

如果用name索引查找数据需要遍历name字段联合索引树,然后根据遍历出来的主键值去主键索引树里再去查出最终数据,成本比全表扫描还高。
可以用覆盖索引优化,这样只需要遍历name字段的联合索引树就可以拿到所有的结果。

EXPLAIN select name,age,position from employees where name > 'a';

可以看到通过select出的字段是覆盖索引,MySQL底层使用了索引优化。
在看另一个case:

EXPLAIN select * from employees where name > 'zzz';

对于上面的这两种 name>‘a‘ 和 name>‘zzz‘的执行结果, mysql最终是否选择走索引或者一张表涉及多个索引, mysql最终如何选择索引,可以通过trace工具来一查究竟,开启trace工具会影响mysql性能,所以只能临时分析sql使用,用完之后需要立即关闭。

SET SESSION optimizer_trace="enabled=on",end_markers_in_json=on;  --开启trace
SELECT * FROM employees WHERE name > 'a' ORDER BY position;
SELECT * FROM information_schema.OPTIMIZER_TRACE;

查看trace字段:
{
  "steps": [
    {
      "join_preparation": {  --第一阶段:SQl准备阶段
        "select#": 1,
        "steps": [
          {
            "expanded_query": "/* select#1 */ select `employees`.`id` AS `id`,`employees`.`name` AS `name`,`employees`.`age` AS `age`,`employees`.`position` AS `position`,`employees`.`hire_time` AS `hire_time` from `employees` where (`employees`.`name` > 'a') order by `employees`.`position`"
          }
        ] /* steps */
      } /* join_preparation */
    },
    {
      "join_optimization": { --第二阶段:SQL优化阶段
        "select#": 1,
        "steps": [
          {
            "condition_processing": { --条件处理
              "condition": "WHERE",
              "original_condition": "(`employees`.`name` > 'a')",
              "steps": [
                {
                  "transformation": "equality_propagation",
                  "resulting_condition": "(`employees`.`name` > 'a')"
                },
                {
                  "transformation": "constant_propagation",
                  "resulting_condition": "(`employees`.`name` > 'a')"
                },
                {
                  "transformation": "trivial_condition_removal",
                  "resulting_condition": "(`employees`.`name` > 'a')"
                }
              ] /* steps */
            } /* condition_processing */
          },
          {
            "table_dependencies": [  --表依赖详情
              {
                "table": "`employees`",
                "row_may_be_null": false,
                "map_bit": 0,
                "depends_on_map_bits": [
                ] /* depends_on_map_bits */
              }
            ] /* table_dependencies */
          },
          {
            "ref_optimizer_key_uses": [
            ] /* ref_optimizer_key_uses */
          },
          {
            "rows_estimation": [  --预估标的访问成本
              {
                "table": "`employees`",
                "range_analysis": {
                  "table_scan": { --全表扫描情况
                    "rows": 3,  --扫描行数
                    "cost": 3.7  --查询成本
                  } /* table_scan */,
                  "potential_range_indices": [  --查询可能使用的索引
                    {
                      "index": "PRIMARY", --主键索引
                      "usable": false,
                      "cause": "not_applicable"
                    },
                    {
                      "index": "idx_name_age_position",  --辅助索引
                      "usable": true,
                      "key_parts": [
                        "name",
                        "age",
                        "position",
                        "id"
                      ] /* key_parts */
                    },
                    {
                      "index": "idx_age",
                      "usable": false,
                      "cause": "not_applicable"
                    }
                  ] /* potential_range_indices */,
                  "setup_range_conditions": [
                  ] /* setup_range_conditions */,
                  "group_index_range": {
                    "chosen": false,
                    "cause": "not_group_by_or_distinct"
                  } /* group_index_range */,
                  "analyzing_range_alternatives": {  ‐‐分析各个索引使用成本
                    "range_scan_alternatives": [
                      {
                        "index": "idx_name_age_position",
                        "ranges": [
                          "a < name"
                        ] /* ranges */,
                        "index_dives_for_eq_ranges": true,
                        "rowid_ordered": false,
                        "using_mrr": false,
                        "index_only": false,  ‐‐是否使用覆盖索引
                        "rows": 3,  --‐‐索引扫描行数
                        "cost": 4.61,  --索引使用成本
                        "chosen": false,  ‐‐是否选择该索引
                        "cause": "cost"
                      }
                    ] /* range_scan_alternatives */,
                    "analyzing_roworder_intersect": {
                      "usable": false,
                      "cause": "too_few_roworder_scans"
                    } /* analyzing_roworder_intersect */
                  } /* analyzing_range_alternatives */
                } /* range_analysis */
              }
            ] /* rows_estimation */
          },
          {
            "considered_execution_plans": [
              {
                "plan_prefix": [
                ] /* plan_prefix */,
                "table": "`employees`",
                "best_access_path": {
                  "considered_access_paths": [
                    {
                      "access_type": "scan",
                      "rows": 3,
                      "cost": 1.6,
                      "chosen": true,
                      "use_tmp_table": true
                    }
                  ] /* considered_access_paths */
                } /* best_access_path */,
                "cost_for_plan": 1.6,
                "rows_for_plan": 3,
                "sort_cost": 3,
                "new_cost_for_plan": 4.6,
                "chosen": true
              }
            ] /* considered_execution_plans */
          },
          {
            "attaching_conditions_to_tables": {
              "original_condition": "(`employees`.`name` > 'a')",
              "attached_conditions_computation": [
              ] /* attached_conditions_computation */,
              "attached_conditions_summary": [
                {
                  "table": "`employees`",
                  "attached": "(`employees`.`name` > 'a')"
                }
              ] /* attached_conditions_summary */
            } /* attaching_conditions_to_tables */
          },
          {
            "clause_processing": {
              "clause": "ORDER BY",
              "original_clause": "`employees`.`position`",
              "items": [
                {
                  "item": "`employees`.`position`"
                }
              ] /* items */,
              "resulting_clause_is_simple": true,
              "resulting_clause": "`employees`.`position`"
            } /* clause_processing */
          },
          {
            "refine_plan": [
              {
                "table": "`employees`",
                "access_type": "table_scan"
              }
            ] /* refine_plan */
          },
          {
            "reconsidering_access_paths_for_index_ordering": {
              "clause": "ORDER BY",
              "index_order_summary": {
                "table": "`employees`",
                "index_provides_order": false,
                "order_direction": "undefined",
                "index": "unknown",
                "plan_changed": false
              } /* index_order_summary */
            } /* reconsidering_access_paths_for_index_ordering */
          }
        ] /* steps */
      } /* join_optimization */
    },
    {
      "join_execution": {  --第三阶段:SQL执行阶段
        "select#": 1,
        "steps": [
          {
            "filesort_information": [
              {
                "direction": "asc",
                "table": "`employees`",
                "field": "position"
              }
            ] /* filesort_information */,
            "filesort_priority_queue_optimization": {
              "usable": false,
              "cause": "not applicable (no LIMIT)"
            } /* filesort_priority_queue_optimization */,
            "filesort_execution": [
            ] /* filesort_execution */,
            "filesort_summary": {
              "rows": 3,
              "examined_rows": 3,
              "number_of_tmp_files": 0,
              "sort_buffer_size": 200704,
              "sort_mode": "<sort_key, additional_fields>"
            } /* filesort_summary */
          }
        ] /* steps */
      } /* join_execution */
    }
  ] /* steps */
}

全表扫描的成本低于索引扫描, 索引MySQL最终会选择全表扫描。

SELECT * FROM employees WHERE name > 'zzz' ORDER BY position;
SELECT * FROM information_schema.OPTIMIZER_TRACE;

{
  "steps": [
    {
      "join_preparation": {
        "select#": 1,
        "steps": [
          {
            "expanded_query": "/* select#1 */ select `employees`.`id` AS `id`,`employees`.`name` AS `name`,`employees`.`age` AS `age`,`employees`.`position` AS `position`,`employees`.`hire_time` AS `hire_time` from `employees` where (`employees`.`name` > 'zzz') order by `employees`.`position`"
          }
        ] /* steps */
      } /* join_preparation */
    },
    {
      "join_optimization": {
        "select#": 1,
        "steps": [
          {
            "condition_processing": {
              "condition": "WHERE",
              "original_condition": "(`employees`.`name` > 'zzz')",
              "steps": [
                {
                  "transformation": "equality_propagation",
                  "resulting_condition": "(`employees`.`name` > 'zzz')"
                },
                {
                  "transformation": "constant_propagation",
                  "resulting_condition": "(`employees`.`name` > 'zzz')"
                },
                {
                  "transformation": "trivial_condition_removal",
                  "resulting_condition": "(`employees`.`name` > 'zzz')"
                }
              ] /* steps */
            } /* condition_processing */
          },
          {
            "table_dependencies": [
              {
                "table": "`employees`",
                "row_may_be_null": false,
                "map_bit": 0,
                "depends_on_map_bits": [
                ] /* depends_on_map_bits */
              }
            ] /* table_dependencies */
          },
          {
            "ref_optimizer_key_uses": [
            ] /* ref_optimizer_key_uses */
          },
          {
            "rows_estimation": [
              {
                "table": "`employees`",
                "range_analysis": {
                  "table_scan": {
                    "rows": 3,
                    "cost": 3.7
                  } /* table_scan */,
                  "potential_range_indices": [
                    {
                      "index": "PRIMARY",
                      "usable": false,
                      "cause": "not_applicable"
                    },
                    {
                      "index": "idx_name_age_position",
                      "usable": true,
                      "key_parts": [
                        "name",
                        "age",
                        "position",
                        "id"
                      ] /* key_parts */
                    },
                    {
                      "index": "idx_age",
                      "usable": false,
                      "cause": "not_applicable"
                    }
                  ] /* potential_range_indices */,
                  "setup_range_conditions": [
                  ] /* setup_range_conditions */,
                  "group_index_range": {
                    "chosen": false,
                    "cause": "not_group_by_or_distinct"
                  } /* group_index_range */,
                  "analyzing_range_alternatives": {
                    "range_scan_alternatives": [
                      {
                        "index": "idx_name_age_position",
                        "ranges": [
                          "zzz < name"
                        ] /* ranges */,
                        "index_dives_for_eq_ranges": true,
                        "rowid_ordered": false,
                        "using_mrr": false,
                        "index_only": false,
                        "rows": 1,
                        "cost": 2.21,
                        "chosen": true
                      }
                    ] /* range_scan_alternatives */,
                    "analyzing_roworder_intersect": {
                      "usable": false,
                      "cause": "too_few_roworder_scans"
                    } /* analyzing_roworder_intersect */
                  } /* analyzing_range_alternatives */,
                  "chosen_range_access_summary": {
                    "range_access_plan": {
                      "type": "range_scan",
                      "index": "idx_name_age_position",
                      "rows": 1,
                      "ranges": [
                        "zzz < name"
                      ] /* ranges */
                    } /* range_access_plan */,
                    "rows_for_plan": 1,
                    "cost_for_plan": 2.21,
                    "chosen": true
                  } /* chosen_range_access_summary */
                } /* range_analysis */
              }
            ] /* rows_estimation */
          },
          {
            "considered_execution_plans": [
              {
                "plan_prefix": [
                ] /* plan_prefix */,
                "table": "`employees`",
                "best_access_path": {
                  "considered_access_paths": [
                    {
                      "access_type": "range",
                      "rows": 1,
                      "cost": 2.41,
                      "chosen": true,
                      "use_tmp_table": true
                    }
                  ] /* considered_access_paths */
                } /* best_access_path */,
                "cost_for_plan": 2.41,
                "rows_for_plan": 1,
                "sort_cost": 1,
                "new_cost_for_plan": 3.41,
                "chosen": true
              }
            ] /* considered_execution_plans */
          },
          {
            "attaching_conditions_to_tables": {
              "original_condition": "(`employees`.`name` > 'zzz')",
              "attached_conditions_computation": [
              ] /* attached_conditions_computation */,
              "attached_conditions_summary": [
                {
                  "table": "`employees`",
                  "attached": "(`employees`.`name` > 'zzz')"
                }
              ] /* attached_conditions_summary */
            } /* attaching_conditions_to_tables */
          },
          {
            "clause_processing": {
              "clause": "ORDER BY",
              "original_clause": "`employees`.`position`",
              "items": [
                {
                  "item": "`employees`.`position`"
                }
              ] /* items */,
              "resulting_clause_is_simple": true,
              "resulting_clause": "`employees`.`position`"
            } /* clause_processing */
          },
          {
            "refine_plan": [
              {
                "table": "`employees`",
                "pushed_index_condition": "(`employees`.`name` > 'zzz')",
                "table_condition_attached": null,
                "access_type": "range"
              }
            ] /* refine_plan */
          },
          {
            "reconsidering_access_paths_for_index_ordering": {
              "clause": "ORDER BY",
              "index_order_summary": {
                "table": "`employees`",
                "index_provides_order": false,
                "order_direction": "undefined",
                "index": "idx_name_age_position",
                "plan_changed": false
              } /* index_order_summary */
            } /* reconsidering_access_paths_for_index_ordering */
          }
        ] /* steps */
      } /* join_optimization */
    },
    {
      "join_execution": {
        "select#": 1,
        "steps": [
          {
            "filesort_information": [
              {
                "direction": "asc",
                "table": "`employees`",
                "field": "position"
              }
            ] /* filesort_information */,
            "filesort_priority_queue_optimization": {
              "usable": false,
              "cause": "not applicable (no LIMIT)"
            } /* filesort_priority_queue_optimization */,
            "filesort_execution": [
            ] /* filesort_execution */,
            "filesort_summary": {
              "rows": 0,
              "examined_rows": 0,
              "number_of_tmp_files": 0,
              "sort_buffer_size": 200704,
              "sort_mode": "<sort_key, additional_fields>"
            } /* filesort_summary */
          }
        ] /* steps */
      } /* join_execution */
    }
  ] /* steps */
}

查看trace字段可知索引扫描的成本低于全表扫描的成本,所以MySQL最终选择索引扫描。

SET SESSION optimizer_trace="enabled=off"; -- 关闭trace

还没关注我的公众号?

  • 扫文末二维码关注公众号【小强的进阶之路】可领取如下:
  • 学习资料: 1T视频教程:涵盖Javaweb前后端教学视频、机器学习/人工智能教学视频、Linux系统教程视频、雅思考试视频教程;
  • 100多本书:包含C/C++、Java、Python三门编程语言的经典必看图书、LeetCode题解大全;
  • 软件工具:几乎包括你在编程道路上的可能会用到的大部分软件;
  • 项目源码:20个JavaWeb项目源码。

原文地址:https://www.cnblogs.com/xiaoqiang-code/p/11474036.html

时间: 2024-10-09 15:11:17

MySQL如何选择合适的索引的相关文章

MySQL 请选择合适的列! 转载(http://www.cnblogs.com/baochuan/archive/2012/05/23/2513224.html)

点击图片,可查看大图. 介绍 情况:如果你的表结构设计不良或你的索引设计不佳,那么请你优化你的表结构设计和给予合适的索引,这样你的查询性能就能提高几个数量级.——数据越大,索引的价值越能体现出来. 我们要提高性能,需要考虑的因素: 1.设计架构 2.设计索引 3.评估查询性能 今天要讲的是表列的设计,暂不谈索引设计.我会在下一章讲索引设计. 选择数据类型 选择正确的数据类型,对于提高性能至关重要. 下面给出几种原则,有利于帮助你选择何种类型. 1.更小通常更好. 使用最小的数据类型.——更少的磁

mysql如何选择合适的数据类型1:CHAR与VARCHAR

CHAR和VARCHAR类型类似,都用来存储字符串,但它们"保存"和"检索"的方式不同.CHAR属于"固定长度"的字符串,而VARCHAR属于"可变长度"的字符类型. 下表显示了将各种字符串值保存到CHAR(4)和VARCHAR(4)列后的结果,说明了CHAR和VARCHAR之间的差别. CHAR和VARCHAR的对比 值 CHAR(4) 存储需求 VARCHAR(4) 存储需求 '' '    ' 4个字节 '' 1个字节

mysql 什么时候用单列索引?什么使用用联合索引?

我一个表 students 表,有3个字段 ,id,name,age 我要查询 通过 name 和age,在这两个字段 是创建 联合索引?还是分别在nage和age上创建 单列索引呢? 多个字段查询什么情况下用联合索引 什么时候分别创建单列索引呢? 作者:范孝鹏链接:https://www.zhihu.com/question/40736083/answer/88191544来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 1,首先要确定优化的目标,在什么样的业务场

MYSQL 什么时候用单列索引?什么使用用联合索引?(收集)

我一个表 students 表,有3个字段 ,id,name,age 我要查询 通过 name 和age,在这两个字段 是创建 联合索引?还是分别在name和age上创建 单列索引呢? 多个字段查询什么情况下用联合索引 什么时候分别创建单列索引呢? 1,首先要确定优化的目标,在什么样的业务场景下,表的大小等等.如果表比较小的话,可能都不需要加索引. 2,哪些字段可以建索引,一般都where.order by 或者 group by 后面的字段. 3,记录修改的时候需要维护索引,所以会有开销,要衡

小蚂蚁学习mysql性能优化(7)--数据库结构优化--选择合适的数据类型

关于SQL以及索引优化的部分终于学习完了,今天开始进入第二层次的学习,数据库的结构优化,第一部分,选择合适的数据类型. 数据类型的选择,重点在于合适二字. 1.    使用可以存下数据的最小的数据类型 比如,一个时间类型的一个数据,可以使用varchar,可以使用datetime,还可以使用int,如何选择,就看哪一种类型对我们来说是最小的,不言而喻,int类型相对来说是最小的数据类型. 2.    使用简单的数据类型. int类型要比varchar类型在mysql处理上简单的多,用int类型来

为MySQL选择合适的备份方式

数据库的备份是极其重要的事情.如果没有备份,遇到下列情况就会抓狂: UPDATE or DELETE whitout where- table was DROPPed accidentally- INNODB was corrupt- entire datacenter loses power- 从数据安全的角度来说,服务器磁盘都会做raid,MySQL本身也有主从.drbd等容灾机制,但它们都无法完全取代备份.容灾和高可用能帮我们 有效的应对物理的.硬件的.机械的故障,而对我们犯下的逻辑错误却

mysql选择合适的数据类型

MySQL之选择字段数据类型 MySQL支持的数据类型很多,选择正确的数据类型对于 获得高性能至关重要.在选择时有个简单的原则有助于做出更好的选择. 简单的原则: A.通常最小的是最好的 因为这样可以用更少的磁盘.内容.CPU缓存,大大减少IO开销. B.简单就好 简单的数据类型操作通常需要更少的CPU周期.例如,整型比字符操作代价更小,因为字符集和校对规则(排序规则)使它比整型更复杂.比如应该使用MySQL内建的类型而不是使用字符型来存储日期和时间. C.尽量避免使用NULL NULL是列默认

结合mysql查询优化器对联合索引的探讨

无陈述,直接开讲: babysitter_account表中的联合索引如下(开发小伙伴们自建的联合索引.您发现不妥了吗?): KEY `flag` (`flag`,`user_id`,`account_id`) 过去认为: 1.SELECT account_id,weibo_id,weibo_type FROM babysitter_account WHERE user_id BETWEEN 100 and 10000 AND flag=0; 2.SELECT account_id,weibo_

Hadoop集群选择合适的硬件配置

为Hadoop集群选择合适的硬件配置 随着Apache Hadoop的起步,云客户的增多面临的首要问题就是如何为他们新的的Hadoop集群选择合适的硬件. 尽管Hadoop被设计为运行在行业标准的硬件上,提出一个理想的集群配置不想提供硬件规格列表那么简单. 选择硬件,为给定的负载在性能和经济性提供最佳平衡是需要测试和验证其有效性.(比如,IO密集型工作负载的用户将会为每个核心主轴投资更多). 在这个博客帖子中,你将会学到一些工作负载评估的原则和它在硬件选择中起着至关重要的作用.在这个过程中,你也