MySQL 执行计划explain与索引数据结构推演过程是什么

53次阅读
没有评论

共计 15421 个字符,预计需要花费 39 分钟才能阅读完成。

自动写代码机器人,免费开通

了解 MySQL 执行计划 explain 与索引数据结构推演过程是什么?这个问题可能是我们日常学习或工作经常见到的。希望通过这个问题能让你收获颇深。下面是丸趣 TV 小编给大家带来的参考内容,让我们一起来看看吧!

先建好数据库表,演示用的 MySQL 表,建表语句:

CREATE TABLE `emp` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 主键 , `empno` int(11) DEFAULT NULL COMMENT 雇员工号 , `ename` varchar(255) DEFAULT NULL COMMENT 雇员姓名 , `job` varchar(255) DEFAULT NULL COMMENT 工作 , `mgr` varchar(255) DEFAULT NULL COMMENT 经理的工号 , `hiredate` date DEFAULT NULL COMMENT 雇用日期 , `sal` double DEFAULT NULL COMMENT 工资 , `comm` double DEFAULT NULL COMMENT 津贴 , `deptno` int(11) DEFAULT NULL COMMENT 所属部门号 ,
 PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT= 雇员表 CREATE TABLE `dept` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 主键 , `deptno` int(11) DEFAULT NULL COMMENT 部门号 , `dname` varchar(255) DEFAULT NULL COMMENT 部门名称 , `loc` varchar(255) DEFAULT NULL COMMENT 地址 ,
 PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT= 部门表 CREATE TABLE `salgrade` (`id` int(11) NOT NULL COMMENT 主键 , `grade` varchar(255) DEFAULT NULL COMMENT 等级 , `lowsal` varchar(255) DEFAULT NULL COMMENT 最低工资 , `hisal` varchar(255) DEFAULT NULL COMMENT 最高工资 ,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT= 工资等级表 CREATE TABLE `bonus` (`id` int(11) NOT NULL COMMENT 主键 , `ename` varchar(255) DEFAULT NULL COMMENT 雇员姓名 , `job` varchar(255) DEFAULT NULL COMMENT 工作 , `sal` double DEFAULT NULL COMMENT 工资 , `comm` double DEFAULT NULL COMMENT 津贴 ,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT= 奖金表 复制代码

后续执行计划,查询优化,索引优化等等知识的演练,基于以上几个表来操作。

MySQL 执行计划

要进行 SQL 调优,你得知道要调优的 SQL 语句是怎么执行的,查看 SQL 语句的具体执行过程,以加快 SQL 语句的执行效率。

可以使用 explain + SQL 语句来模拟优化器执行 SQL 查询语句,从而知道 MySQL 是如何处理 SQL 语句的。

关于 explain 可以看看官网介绍。

explain 的输出格式

mysql explain select * from emp;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+| 1 | SIMPLE | emp | NULL | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+ 复制代码

字段 id,select_type 等字段的解释:

ColumnMeaningidThe SELECT identifier(该 SELECT 标识符)select_typeThe SELECT type(该 SELECT 类型)tableThe table for the output row(输出该行的表名)partitionsThe matching partitions(匹配的分区)typeThe join type(连接类型)possible_keysThe possible indexes to choose(可能的索引选择)keyThe index actually chosen(实际选择的索引)key_lenThe length of the chosen key(所选键的长度)refThe columns compared to the index(与索引比较的列)rowsEstimate of rows to be examined(检查的预估行数)filteredPercentage of rows filtered by table condition(按表条件过滤的行百分比)extraAdditional information(附加信息)

id

select 查询的序列号,包含一组数字,表示查询中执行 select 子句或者操作表的顺序。

id 号分为三类:

如果 id 相同,那么执行顺序从上到下

mysql explain select * from emp e join dept d on e.deptno = d.deptno join salgrade sg on e.sal between sg.lowsal and sg.hisal;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
| 1 | SIMPLE | e | NULL | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | NULL |
| 1 | SIMPLE | d | NULL | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | Using where; Using join buffer (Block Nested Loop) |
| 1 | SIMPLE | sg | NULL | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+ 复制代码

这个查询,用 explain 执行一下,id 序号都是 1,那么 MySQL 的执行顺序就是从上到下执行的。

如果 id 不同,如果是子查询,id 的序号会递增,id 值越大优先级越高,越先被执行

mysql explain select * from emp e where e.deptno in (select d.deptno from dept d where d.dname = SALEDept 
+----+--------------+-------------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------+-------------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+| 1 | SIMPLE | subquery2 | NULL | ALL | NULL | NULL | NULL | NULL | NULL | 100.00 | NULL |
| 1 | SIMPLE | e | NULL | ALL | NULL | NULL | NULL | NULL | 2 | 50.00 | Using where; Using join buffer (Block Nested Loop) |
| 2 | MATERIALIZED | d | NULL | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | Using where |
+----+--------------+-------------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+ 复制代码

这个例子的执行顺序是先执行 id 为 2 的,然后执行 id 为 1 的。

id 相同和不同的,同时存在:相同的可以认为是一组,从上往下顺序执行,在所有组中,id 值越大,优先级越高,越先执行

还是上面那个例子,先执行 id 为 2 的,然后按顺序从上往下执行 id 为 1 的。

select_type

主要用来分辨查询的类型,是普通查询还是联合查询还是子查询。

select_type ValueJSON NameMeaningSIMPLENoneSimple SELECT (not using UNION or subqueries)PRIMARYNoneOutermost SELECTUNIONNoneSecond or later SELECT statement in a UNIONDEPENDENT UNIONdependent (true)Second or later SELECT statement in a UNION, dependent on outer queryUNION RESULTunion_resultResult of a UNION.SUBQUERYNoneFirst SELECT in subqueryDEPENDENT SUBQUERYdependent (true)First SELECT in subquery, dependent on outer queryDERIVEDNoneDerived tableMATERIALIZEDmaterialized_from_subqueryMaterialized subqueryUNCACHEABLE SUBQUERYcacheable (false)A subquery for which the result cannot be cached and must be re-evaluated for each row of the outer queryUNCACHEABLE UNIONcacheable (false)The second or later select in a UNION that belongs to an uncacheable subquery (see UNCACHEABLE SUBQUERY)SIMPLE 简单的查询,不包含子查询和 union

mysql explain select * from emp;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+| 1 | SIMPLE | emp | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+ 复制代码

primary 查询中若包含任何复杂的子查询,最外层查询则被标记为 Primaryunion 若第二个 select 出现在 union 之后,则被标记为 union

mysql explain select * from emp where deptno = 1001 union select * from emp where sal 5000;
+----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+| 1 | PRIMARY | emp | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 25.00 | Using where |
| 2 | UNION | emp | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 33.33 | Using where |
| NULL | UNION RESULT | union1,2 | NULL | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+ 复制代码

这条语句的 select_type 包含了 primary 和 union

dependent union 跟 union 类似,此处的 depentent 表示 union 或 union all 联合而成的结果会受外部表影响 union result 从 union 表获取结果的 selectdependent subquery subquery 的子查询要受到外部表查询的影响

mysql explain select * from emp e where e.empno in (select empno from emp where deptno = 1001 union select empno from emp where sal 5000);
+----+--------------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+| 1 | PRIMARY | e | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 100.00 | Using where |
| 2 | DEPENDENT SUBQUERY | emp | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 25.00 | Using where |
| 3 | DEPENDENT UNION | emp | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 25.00 | Using where |
| NULL | UNION RESULT | union2,3 | NULL | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+ 复制代码

这条 SQL 执行包含了 PRIMARY、DEPENDENT SUBQUERY、DEPENDENT UNION 和 UNION RESULT

subquery 在 select 或者 where 列表中包含子查询

举例:

mysql explain select * from emp where sal (select avg(sal) from emp) ;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+| 1 | PRIMARY | emp | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 33.33 | Using where |
| 2 | SUBQUERY | emp | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ 复制代码

DERIVED from 子句中出现的子查询,也叫做派生表 MATERIALIZED Materialized subquery?UNCACHEABLE SUBQUERY 表示使用子查询的结果不能被缓存

例如:

mysql explain select * from emp where empno = (select empno from emp where deptno=@@sort_buffer_size);
+----+----------------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+----------------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+| 1 | PRIMARY | emp | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 100.00 | Using where |
| 2 | UNCACHEABLE SUBQUERY | emp | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 25.00 | Using where |
+----+----------------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ 复制代码

uncacheable union 表示 union 的查询结果不能被缓存

table

对应行正在访问哪一个表,表名或者别名,可能是临时表或者 union 合并结果集。

如果是具体的表名,则表明从实际的物理表中获取数据,当然也可以是表的别名表名是 derivedN 的形式,表示使用了 id 为 N 的查询产生的衍生表当有 union result 的时候,表名是 union n1,n2 等的形式,n1,n2 表示参与 union 的 id

type

type 显示的是访问类型,访问类型表示我是以何种方式去访问我们的数据,最容易想到的是全表扫描,直接暴力的遍历一张表去寻找需要的数据,效率非常低下。

访问的类型有很多,效率从最好到最坏依次是:

system const eq_ref ref fulltext ref_or_null index_merge unique_subquery index_subquery range index ALL

一般情况下,得保证查询至少达到 range 级别,最好能达到 ref

all 全表扫描,一般情况下出现这样的 sql 语句而且数据量比较大的话那么就需要进行优化

通常,可以通过添加索引来避免 ALL

index 全索引扫描这个比 all 的效率要好,主要有两种情况:一种是当前的查询时覆盖索引,即我们需要的数据在索引中就可以索取一是使用了索引进行排序,这样就避免数据的重排序 range 表示利用索引查询的时候限制了范围,在指定范围内进行查询,这样避免了 index 的全索引扫描,适用的操作符:=, , , =, , =, IS NULL, BETWEEN, LIKE, or IN()

官网上举例如下:

SELECT * FROM tbl_name
WHERE key_column = 10;

SELECT * FROM tbl_name
WHERE key_column BETWEEN 10 and 20;

SELECT * FROM tbl_name
WHERE key_column IN (10,20,30);

SELECT * FROM tbl_name
WHERE key_part1 = 10 AND key_part2 IN (10,20,30);

index_subquery 利用索引来关联子查询,不再扫描全表

value IN (SELECT key_column FROM single_table WHERE some_expr)

unique_subquery 该连接类型类似与 index_subquery,使用的是唯一索引

value IN (SELECT primary_key FROM single_table WHERE some_expr)

index_merge 在查询过程中需要多个索引组合使用 ref_or_null 对于某个字段既需要关联条件,也需要 null 值的情况下,查询优化器会选择这种访问方式

SELECT * FROM ref_table

WHERE key_column=expr OR key_column IS NULL;

fulltext 使用 FULLTEXT 索引执行 joinref 使用了非唯一性索引进行数据的查找

SELECT * FROM ref_table WHERE key_column=expr;

SELECT * FROM ref_table,other_table
WHERE ref_table.key_column=other_table.column;

SELECT * FROM ref_table,other_table
WHERE ref_table.key_column_part1=other_table.column
AND ref_table.key_column_part2=1;

eq_ref 使用唯一性索引进行数据查找

SELECT * FROM ref_table,other_table
WHERE ref_table.key_column=other_table.column;

SELECT * FROM ref_table,other_table
WHERE ref_table.key_column_part1=other_table.column
AND ref_table.key_column_part2=1;

const 这个表至多有一个匹配行

SELECT * FROM tbl_name WHERE primary_key=1;

SELECT * FROM tbl_name
WHERE primary_key_part1=1 AND primary_key_part2=2;

例如:

mysql explain select * from emp where id = 1;
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+| 1 | SIMPLE | emp | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+ 复制代码

system 表只有一行记录(等于系统表),这是 const 类型的特例,平时不会出现

possible_keys

显示可能应用在这张表中的索引,一个或多个,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用

MySQL 执行计划 explain 与索引数据结构推演过程是什么

key

实际使用的索引,如果为 null,则没有使用索引,查询中若使用了覆盖索引,则该索引和查询的 select 字段重叠

MySQL 执行计划 explain 与索引数据结构推演过程是什么

key_len

表示索引中使用的字节数,可以通过 key_len 计算查询中使用的索引长度,在不损失精度的情况下长度越短越好

ref

显示索引的哪一列被使用了,如果可能的话,是一个常数

rows

根据表的统计信息及索引使用情况,大致估算出找出所需记录需要读取的行数,此参数很重要,直接反应的 sql 找了多少数据,在完成目的的情况下越少越好

MySQL 执行计划 explain 与索引数据结构推演过程是什么

extra

包含额外的信息

using filesort 说明 mysql 无法利用索引进行排序,只能利用排序算法进行排序,会消耗额外的位置 using temporary 建立临时表来保存中间结果,查询完成之后把临时表删除 using index 这个表示当前的查询是覆盖索引的,直接从索引中读取数据,而不用访问数据表。如果同时出现 using where 表明索引被用来执行索引键值的查找,如果没有,表示索引被用来读取数据,而不是真的查找 using where 使用 where 进行条件过滤 using join buffer 使用连接缓存 impossible where where 语句的结果总是 falseMySQL 索引基本知识

想要了解索引的优化方式,必须要对索引的底层原理有所了解。

索引的优点大大减少了服务器需要扫描的数据量帮助服务器避免排序和临时表将随机 io 变成顺序 io(提升效率)索引的用处快速查找匹配 WHERE 子句的行从 consideration 中消除行, 如果可以在多个索引之间进行选择,mysql 通常会使用找到最少行的索引如果表具有多列索引,则优化器可以使用索引的任何最左前缀来查找行当有表连接的时候,从其他表检索行数据查找特定索引列的 min 或 max 值如果排序或分组时在可用索引的最左前缀上完成的,则对表进行排序和分组在某些情况下,可以优化查询以检索值而无需查询数据行索引的分类

MySQL 执行计划 explain 与索引数据结构推演过程是什么

MySQL 索引数据结构推演

索引用于快速查找具有特定列值的行。

如果没有索引,MySQL 必须从第一行开始,然后通读整个表以找到相关的行。

表越大花费的时间越多,如果表中有相关列的索引,MySQL 可以快速确定要在数据文件中间查找的位置,而不必查看所有数据。这比顺序读取每一行要快得多。

既然 MySQL 索引能帮助我们快速查询到数据,那么它的底层是怎么存储数据的呢?

几种可能的存储结构

hash

hash 表的索引格式

MySQL 执行计划 explain 与索引数据结构推演过程是什么

hash 表存储数据的缺点:

利用 hash 存储的话需要将所有的数据文件添加到内存,比较耗费内存空间如果所有的查询都是等值查询,那么 hash 确实很快,但是在实际工作环境中范围查找的数据更多一些,而不是等值查询,这种情况下 hash 就不太适合了

事实上,MySQL 存储引擎是 memory 时,索引数据结构采用的就是 hash 表。

二叉树

二叉树的结构是这样的:

MySQL 执行计划 explain 与索引数据结构推演过程是什么

二叉树会因为树的深度而造成数据倾斜,如果树的深度过深,会造成 io 次数变多,影响数据读取的效率。

AVL 树 需要旋转,看图例:

MySQL 执行计划 explain 与索引数据结构推演过程是什么

红黑树 除了旋转操作还多了一个变色的功能(为了减少旋转),这样虽然插入的速度快,但是损失了查询的效率。

MySQL 执行计划 explain 与索引数据结构推演过程是什么

二叉树、AVL 树、红黑树 都会因为树的深度过深而造成 io 次数变多,影响数据读取的效率。

再来看一下 B 树

B 树特点:

所有键值分布在整颗树中搜索有可能在非叶子结点结束,在关键字全集内做一次查找, 性能逼近二分查找每个节点最多拥有 m 个子树根节点至少有 2 个子树分支节点至少拥有 m / 2 颗子树(除根节点和叶子节点外都是分支节点)所有叶子节点都在同一层、每个节点最多可以有 m - 1 个 key,并且以升序排列

MySQL 执行计划 explain 与索引数据结构推演过程是什么

图例说明:

每个节点占用一个磁盘块,一个节点上有两个升序排序的关键字和三个指向子树根节点的指针,指针存储的是子节点所在磁盘块的地址。

两个关键词划分成的三个范围域对应三个指针指向的子树的数据的范围域。

以根节点为例,关键字为 16 和 34,P1 指针指向的子树的数据范围为小于 16,P2 指针指向的子树的数据范围为 16~34,P3 指针指向的子树的数据范围为大于 34。

查找关键字过程:

1、根据根节点找到磁盘块 1,读入内存。【磁盘 I/O 操作第 1 次】

2、比较关键字 28 在区间(16,34),找到磁盘块 1 的指针 P2。

3、根据 P2 指针找到磁盘块 3,读入内存。【磁盘 I/O 操作第 2 次】

4、比较关键字 28 在区间(25,31),找到磁盘块 3 的指针 P2。

5、根据 P2 指针找到磁盘块 8,读入内存。【磁盘 I/O 操作第 3 次】

6、在磁盘块 8 中的关键字列表中找到关键字 28。

由此,我们可以得知 B 树存储的缺点:

每个节点都有 key,同时也包含 data,而每个页存储空间是有限的,如果 data 比较大的话会导致每个节点存储的 key 数量变小当存储的数据量很大的时候会导致深度较大,增大查询时磁盘 io 次数,进而影响查询性能那么 MySQL 索引数据结构是什么呢

官网:Most MySQL indexes (PRIMARY KEY, UNIQUE, INDEX, and FULLTEXT) are stored in B-trees

不要误会,其实 MySQL 索引的存储结构是 B + 树,上面我们一顿分析,知道 B 树是不合适的。

mysql 索引数据结构 —B+Tree

B+Tree 是在 BTree 的基础之上做的一种优化,变化如下:

1、B+Tree 每个节点可以包含更多的节点,这个做的原因有两个,第一个原因是为了降低树的高度,第二个原因是将数据范围变为多个区间,区间越多,数据检索越快。

2、非叶子节点存储 key,叶子节点存储 key 和数据。

3、叶子节点两两指针相互连接(符合磁盘的预读特性),顺序查询性能更高。

B+ 树存储查找示意图:

MySQL 执行计划 explain 与索引数据结构推演过程是什么

注意:

在 B +Tree 上有两个头指针,一个指向根节点,另一个指向关键字最小的叶子节点,而且所有叶子节点(即数据节点)之间是一种链式环结构。

因此可以对 B+Tree 进行两种查找运算:一种是对于主键的范围查找和分页查找,另一种是从根节点开始,进行随机查找。

由于 B + 树叶子结点只存放 data,根节点只存放 key,那么我们计算一下,即使只有 3 层 B + 树,也能制成千万级别的数据。

你得知道的技(zhuang)术(b)名词

假设有这样一个表如下,其中 id 是主键:

mysql select * from stu;
+------+---------+------+| id | name | age |
+------+---------+------+| 1 | Jack Ma | 18 |
| 2 | Pony | 19 |
+------+---------+------+ 复制代码

回表

我们对普通列建普通索引,这时候我们来查:

select * from stu where name= Pony 复制代码

由于 name 建了索引,查询时先找 name 的 B + 树,找到主键 id 后,再找主键 id 的 B + 树,从而找到整行记录。

这个最终会回到主键上来查找 B + 树,这个就是回表。

覆盖索引

如果是这个查询:

mysql select id from stu where name= Pony 复制代码

就没有回表了,因为直接找到主键 id,返回就完了,不需要再找其他的了。

没有回表就叫覆盖索引。

最左匹配

再来以 name 和 age 两个字段建组合索引(name, age),然后有这样一个查询:

select * from stu where name=? and age=? 复制代码

这时按照组合索引 (name, age) 查询,先匹配 name,再匹配 age,如果查询变成这样:

select * from stu where age=? 复制代码

直接不按 name 查了,此时索引不会生效,也就是不会按照索引查询 — 这就是最左匹配原则。

加入我就要按 age 查,还要有索引来优化呢?可以这样做:

(推荐)把组合索引 (name, age) 换个顺序,建 (age, name) 索引或者直接把 age 字段单独建个索引索引下推

可能也叫谓词下推。。。

select t1.name,t2.name from t1 join t2 on t1.id=t2.id 复制代码

t1 有 10 条记录,t2 有 20 条记录。

我们猜想一下,这个要么按这个方式执行:

先 t1,t2 按 id 合并(合并后 20 条),然后再查 t1.name,t2.name

或者:

先把 t1.name,t2.name 找出来,再按照 id 关联

如果不使用索引条件下推优化的话,MySQL 只能根据索引查询出 t1,t2 合并后的所有行,然后再依次比较是否符合全部条件。

当使用了索引条件下推优化技术后,可以通过索引中存储的数据判断当前索引对应的数据是否符合条件,只有符合条件的数据才将整行数据查询出来。

小结 Explain 为了知道优化 SQL 语句的执行,需要查看 SQL 语句的具体执行过程,以加快 SQL 语句的执行效率。索引优点及用处。索引采用的数据结构是 B + 树。回表,覆盖索引,最左匹配和索引下推。

感谢各位的阅读!看完上述内容,你们对 MySQL 执行计划 explain 与索引数据结构推演过程是什么大概了解了吗?希望文章内容对大家有所帮助。如果想了解更多相关文章内容,欢迎关注丸趣 TV 行业资讯频道。

向 AI 问一下细节

丸趣 TV 网 – 提供最优质的资源集合!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-12-18发表,共计15421字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)