热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

基于物化视图优化_最完整的Explain总结,SQL优化不再困难

先看看具体有哪些字段:mysqlEXPLAINSELECT1;其实除了以SELECT开头的查询语句,其余的DELETE、INSERT、REPLACE以

先看看具体有哪些字段:

mysql> EXPLAIN SELECT 1;

b85239d09599a08868b4808037405c51.png

其实除了以SELECT开头的查询语句,其余的DELETE、INSERT、REPLACE以及UPDATE语句前边都可以加上EXPLAIN这个词儿,用来查看这些语句的执行计划

建两张测试表:

CREATE TABLE t1 (
    id INT NOT NULL AUTO_INCREMENT,
    key1 VARCHAR(100),
    key2 VARCHAR(100),
    key3 VARCHAR(100),
    name VARCHAR(100),
    PRIMARY KEY (id),
    KEY idx_key1 (key1),
    KEY idx_key2_key3(key2, key3)
) Engine=InnoDB CHARSET=utf8;

CREATE TABLE t2 (
    id INT NOT NULL AUTO_INCREMENT,
    key1 VARCHAR(100),
    key2 VARCHAR(100),
    key3 VARCHAR(100),
    name VARCHAR(100),
    PRIMARY KEY (id),
    KEY idx_key1 (key1),
    KEY idx_key2_key3(key2, key3)
) Engine=InnoDB CHARSET=utf8;
两个变种

explain extended

会在 explain 的基础上额外提供一些查询优化的信息。紧随其后通过 show warnings 命令可以 得到优化后的查询语句,从而看出优化器优化了什么

explain extended SELECT * FROM t1 where key1 = '11';
show warnings;

explain partitions

相比 explain 多了个 partitions 字段,如果查询是基于分区表的话,会显示查询将访问的分区。

EXPLAIN PARTITIONS SELECT * FROM t1 INNER JOIN t2 ON t1.key3 = t2.key3;

b2858e841f140e2c7ea00f796efe9b24.png
table列

这一列表示 explain 的一行正在访问哪个表

mysql> EXPLAIN SELECT * FROM t1;

da9b559760ddd984be4df4f406f8a7f0.png

这个查询语句只涉及对t1表的单表查询,所以EXPLAIN输出中只有一条记录,其中的table列的值是t1,表明这条记录是用来说明对t1表的单表访问。

mysql> EXPLAIN SELECT * FROM t1 INNER JOIN t2;

c1e6698fee0cf8cdfbd1229367abeed1.png

可以看到这个连接查询的执行计划中有两条记录,这两条记录的table列分别是t1和t2,这两条记录用来分别说明对t1表和t2表的访问

注意:

当 from 子句中有子查询时,table列是  格式,表示当前查询依赖 id=N 的查询,于是先执行 id=N 的查询。当有 union 时,UNION RESULT 的 table 列的值为,1和2表示参与 union 的 select 行id。

id列

id列的编号是 select 的序列号,有几个 select 就有几个id,并且id的顺序是按 select 出现的顺序增长的。

id列越大执行优先级越高,id相同则从上往下执行,id为NULL最后执行

比如下边这个查询中只有一个SELECT关键字,所以EXPLAIN的结果中也就只有一条id列为1的记录:

mysql> EXPLAIN SELECT * FROM t1 WHERE key1 = 'e038f672a8';

39f55ba31e3914777f070c53cf99f46d.png

对于连接查询来说,一个SELECT关键字后边的FROM子句中可以跟随多个表,所以在连接查询的执行计划中,每个表都会对应一条记录,但是这些记录的id值都是相同的,比如:

mysql> EXPLAIN SELECT * FROM t1 INNER JOIN t2;

f40a2cb02d9010a8750f8175c27e3ab4.png

可以看到,上述连接查询中参与连接的t1和t2表分别对应一条记录,但是这两条记录对应的id值都是1。

注意:

在连接查询的执行计划中,每个表都会对应一条记录,这些记录的id列的值是相同的,出现在前边的表表示驱动表,出现在后边的表表示被驱动表。所以从上边的EXPLAIN输出中我们可以看出,查询优化器准备让t2表作为驱动表,让t1表作为被驱动表来执行查询

对于包含子查询的查询语句来说,就可能涉及多个SELECT关键字,所以在包含子查询的查询语句的执行计划中,每个SELECT关键字都会对应一个唯一的id值,比如这样:

mysql> EXPLAIN SELECT * FROM t1 WHERE key1 IN (SELECT key1 FROM t2) OR key3 = 'a1b6cee57a';

1a7cce85b880c50eafe34cc71e015e44.png

从输出结果中我们可以看到,t1表在外层查询中,外层查询有一个独立的SELECT关键字,所以第一条记录的id值就是1,t2表在子查询中,子查询有一个独立的SELECT关键字,所以第二条记录的id值就是2。

但是这里大家需要特别注意,查询优化器可能对涉及子查询的查询语句进行重写,从而转换为连接查询。所以如果我们想知道查询优化器对某个包含子查询的语句是否进行了重写,直接查看执行计划就好了,比如说:

mysql> EXPLAIN SELECT * FROM t1 WHERE key1 IN (SELECT key3 FROM t2 WHERE t1.key1 = 'a1b6cee57a');

4fa9fac1573abca28ec9cac8ec168a40.png

可以看到,虽然我们的查询语句是一个子查询,但是执行计划中t1和t2表对应的记录的id值全部是1,这就表明了查询优化器将子查询转换为了连接查询。

对于包含UNION子句的查询语句来说,每个SELECT关键字对应一个id值也是没错的,不过还是有点儿特别的东西,比方说下边这个查询:

mysql> EXPLAIN SELECT * FROM t1 UNION SELECT * FROM t2;

7a032ddf3f49b27ec80c0fa45bbf2714.png

UNION子句是为了把id为1的查询和id为2的查询的结果集合并起来并去重,所以在内部创建了一个名为的临时表(就是执行计划第三条记录的table列的名称),id为NULL表明这个临时表是为了合并两个查询的结果集而创建的。

跟UNION对比起来,UNION ALL就不需要为最终的结果集进行去重,它只是单纯的把多个查询的结果集中的记录合并成一个并返回给用户,所以也就不需要使用临时表。所以在包含UNION ALL子句的查询的执行计划中,就没有那个id为NULL的记录,如下所示:

mysql> EXPLAIN SELECT * FROM t1 UNION ALL SELECT * FROM t2;

fe806fa5fe5ccade7efc78d097ff46e1.png
select_type列

MySQL每一个SELECT关键字代表的小查询都定义了一个称之为select_type的属性,意思是我们只要知道了某个小查询的select_type属性,就知道了这个小查询在整个大查询中扮演了一个什么角色

下面是官方文档介绍:

https://dev.mysql.com/doc/refman/5.7/en/explain-output.html#explain_select_type

f7bcaaf94d65154c592e0745d313242f.png

SIMPLE

查询语句中不包含UNION或者子查询的查询都算作是SIMPLE类型,比方说下边这个单表查询的select_type的值就是SIMPLE:

mysql> EXPLAIN SELECT * FROM t1;

5f39daa3c27a504b1d023b8f0394031f.png

PRIMARY

对于包含UNION、UNION ALL或者子查询的大查询来说,它是由几个小查询组成的,其中最左边的那个查询的select_type值就是PRIMARY,比方说:

mysql> EXPLAIN SELECT * FROM t1 UNION SELECT * FROM t2;

b02bb271e204ab568399bc9631222355.png

从结果中可以看到,最左边的小查询SELECT * FROM t1对应的是执行计划中的第一条记录,它的select_type值就是PRIMARY。

UNION

对于包含UNION或者UNION ALL的大查询来说,它是由几个小查询组成的,其中除了最左边的那个小查询以外,其余的小查询的select_type值就是UNION,可以对比上一个例子的效果

UNION RESULT

MySQL选择使用临时表来完成UNION查询的去重工作,针对该临时表的查询的select_type就是UNION RESULT,同样对比上面的例子

SUBQUERY

如果包含子查询的查询语句不能够转为对应的semi-join的形式,并且该子查询是不相关子查询,并且查询优化器决定采用将该子查询物化的方案来执行该子查询时,该子查询的第一个SELECT关键字代表的那个查询的select_type就是SUBQUERY,比如下边这个查询:

概念解释:

semi-join子查询,是指当一张表在另一张表找到匹配的记录之后,半连接(semi-jion)返回第一张表中的记录。与条件连接相反,即使在右节点中找到几条匹配的记录,左节点 的表也只会返回一条记录。另外,右节点的表一条记录也不会返回。半连接通常使用IN 或 EXISTS 作为连接条件

物化:这个将子查询结果集中的记录保存到临时表的过程称之为物化(Materialize)。那个存储子查询结果集的临时表称之为物化表。正因为物化表中的记录都建立了索引(基于内存的物化表有哈希索引,基于磁盘的有B+树索引),通过索引执行IN语句判断某个操作数在不在子查询结果集中变得非常快,从而提升了子查询语句的性能。

mysql> EXPLAIN SELECT * FROM t1 WHERE key1 IN (SELECT key1 FROM t2) OR key3 = 'a1b6cee57a';

f3aeb23e4224e49f3399acb1894ed51f.png

可以看到,外层查询的select_type就是PRIMARY,子查询的select_type就是SUBQUERY。

DEPENDENT SUBQUERY

如果包含子查询的查询语句不能够转为对应的semi-join的形式,并且该子查询是相关子查询,则该子查询的第一个SELECT关键字代表的那个查询的select_type就是DEPENDENT SUBQUERY,比如下边这个查询:

mysql> EXPLAIN SELECT * FROM t1 WHERE key1 IN (SELECT key1 FROM t2 WHERE t1.key2 = t2.key2) OR key3 = 'a1b6cee57a';

ab3e9411d6284152bde43a4a6e1f1599.png

DEPENDENT UNION

在包含UNION或者UNION ALL的大查询中,如果各个小查询都依赖于外层查询的话,那除了最左边的那个小查询之外,其余的小查询的select_type的值就是DEPENDENT UNION。比方说下边这个查询:

mysql> EXPLAIN SELECT * FROM t1 WHERE key1 IN (SELECT key1 FROM t2 WHERE key1 = 'a1b6cee57a' UNION SELECT key1 FROM t1 WHERE key1 = 'a1b6cee57a');

2cb9ac53188a8c8720bc2386b0259597.png

这个查询比较复杂啊,大查询里包含了一个子查询,子查询里又是由UNION连起来的两个小查询。从执行计划中可以看出来,SELECT key1 FROM t2 WHERE key1 = 'a1b6cee57a'这个小查询由于是子查询中第一个查询,所以它的select_type是DEPENDENT SUBQUERY,而SELECT key1 FROM t1 WHERE key1 = 'a1b6cee57a'这个查询的select_type就是DEPENDENT UNION。

DERIVED

对于采用物化的方式执行的包含派生表的查询,该派生表对应的子查询的select_type就是DERIVED,比方说下边这个查询:

mysql> EXPLAIN SELECT * FROM (SELECT key1, count(*) as t FROM t1 GROUP BY key1) AS derived_t1 where t > 1;

20dc5c75622ec8fb908cce4b65dcb28b.png

从执行计划中可以看出,id为2的记录就代表子查询的执行方式,它的select_type是DERIVED,说明该子查询是以物化的方式执行的。id为1的记录代表外层查询,大家注意看它的table列显示的是,表示该查询是针对将派生表物化之后的表进行查询的。

MATERIALIZED

当查询优化器在执行包含子查询的语句时,选择将子查询物化之后与外层查询进行连接查询时,该子查询对应的select_type属性就是MATERIALIZED,比如下边这个查询:

mysql> EXPLAIN SELECT * FROM t1 WHERE key1 IN (SELECT key1 FROM t2);

77fad5965b1d57cb8c419293c32d53bb.png

执行计划的第三条记录的id值为2,说明该条记录对应的是一个单表查询,从它的select_type值为MATERIALIZED可以看出,查询优化器是要把子查询先转换成物化表。然后看执行计划的前两条记录的id值都为1,说明这两条记录对应的表进行连接查询,需要注意的是第二条记录的table列的值是,说明该表其实就是id为2对应的子查询执行之后产生的物化表,然后将s1和该物化表进行连接查询。

type列

这一列表示关联类型或访问类型,即MySQL决定如何查找表中的行,查找数据行记录的大概范围。依次从最优到最差分别为:system > const > eq_ref > ref > range > index > ALL一般来说,得保证查询达到range级别,最好达到ref

NULL

mysql能够在优化阶段分解查询语句,在执行阶段用不着再访问表或索引。例如:在索引列中选取最小值,可以单独查找索引来完成,不需要在执行时访问表

mysql> explain select min(id) from t1;

6994686ecb2fada613795a0cec3b7437.png

eq_ref

primary key 或 unique key 索引的所有部分被连接使用 ,最多只会返回一条符合条件的记录。这可能是在 const 之外最好的联接类型了,简单的 select 查询不会出现这种 type。

在连接查询时,如果被驱动表是通过主键或者唯一二级索引列等值匹配的方式进行访问的(如果该主键或者唯一二级索引是联合索引的话,所有的索引列都必须进行等值比较),则对该被驱动表的访问方法就是eq_ref,比方说:

mysql> EXPLAIN SELECT * FROM t1 INNER JOIN t2 ON t1.id = t2.id;

a1dd33518faba707438b391c4b2dbc76.png

从执行计划的结果中可以看出,MySQL打算将t2作为驱动表,t1作为被驱动表,重点关注t1的访问方法是eq_ref,表明在访问t1表的时候可以通过主键的等值匹配来进行访问。

ref

当通过普通的二级索引列与常量进行等值匹配时来查询某个表,那么对该表的访问方法就可能是ref

相比 eq_ref,不使用唯一索引,而是使用普通索引或者唯一性索引的部分前缀,索引要和某个值相比较,可能会找到多个符合条件的行。

mysql> EXPLAIN SELECT * FROM t1 WHERE key1 = 'a';

fcb03c3620ebb7599981b6c073ea5ac3.png

可以看到type列的值是ref,表明MySQL即将使用ref访问方法来执行对t1表的查询

system,const

mysql能对查询的某部分进行优化并将其转化成一个常量(可以看show warnings 的结果)。用于 primary key 或 unique key 的所有列与常数比较时,所以表最多有一个匹配行,读取1次,速度比较快。system是const的特例,表里只有一条元组匹配时为system

mysql> EXPLAIN SELECT * FROM t1 WHERE id = 5;

f1a3760fc99ac0de7818c2c8e9e3d120.png

ref_or_null

当对普通二级索引进行等值匹配查询,该索引列的值也可以是NULL值时,那么对该表的访问方法就可能是ref_or_null,比如说:

mysql> EXPLAIN SELECT * FROM t1 WHERE key1 = 'a' OR key1 IS NULL;

4495d51385e6ae21b7f48cd842110e08.png

index_merge

一般情况下对于某个表的查询只能使用到一个索引,但在某些场景下可以使用多种索引合并的方式来执行查询,我们看一下执行计划中是怎么体现MySQL使用索引合并的方式来对某个表执行查询的:

mysql> EXPLAIN SELECT * FROM t1 WHERE key1 = 'a' OR key2 = 'a';

2223b79ea544c7fc478c00480952dd10.png

从执行计划的type列的值是index_merge就可以看出,MySQL打算使用索引合并的方式来执行对t1表的查询。

unique_subquery

类似于两表连接中被驱动表的eq_ref访问方法,unique_subquery是针对在一些包含IN子查询的查询语句中,如果查询优化器决定将IN子查询转换为EXISTS子查询,而且子查询可以使用到主键进行等值匹配的话,那么该子查询执行计划的type列的值就是unique_subquery,比如下边的这个查询语句:

mysql> EXPLAIN SELECT * FROM t1 WHERE key2 IN (SELECT id FROM t2 where t1.key1 = t2.key1) OR key3 = 'a';

15dbad76c8391ce1508209c970bc0325.png

可以看到执行计划的第二条记录的type值就是unique_subquery,说明在执行子查询时会使用到id列的索引。

range

范围扫描通常出现在 in(), between ,> ,= 等操作中。使用一个索引来检索给定范围的行。

mysql> EXPLAIN SELECT * FROM t1 WHERE key1 IN ('a', 'b', 'c');

f1357a74e7dc7dadf7f58b0f01d80a73.png

index

当我们可以使用索引覆盖,但需要扫描全部的索引记录时,该表的访问方法就是index

扫描全表索引,这通常比ALL快一些。(index是从索引中读取的,而all是从硬盘中读取)

ALL

最熟悉的全表扫描

mysql> explain select * from t2;

一般来说,这些访问方法按照我们介绍它们的顺序性能依次变差。其中除了All这个访问方法外,其余的访问方法都能用到索引,除了index_merge访问方法外,其余的访问方法都最多只能用到一个索引。

possible_keys和key列

possible_keys列显示查询可能使用哪些索引来查找。

explain 时可能出现 possible_keys 有列,而 key 显示 NULL 的情况,这种情况是因为表中数据不多,mysql认为索引对此查询帮助不大,选择了全表查询。

如果possible_keys列是NULL,则没有相关的索引。在这种情况下,可以通过检查 where 子句看是否可以创造一个适当的索引来提高查询性能,然后用 explain 查看效果。

key列显示mysql实际采用哪个索引来优化对该表的访问。如果没有使用索引,则该列是 NULL。如果想强制mysql使用或忽视possible_keys列中的索引,在查询中使用 force index、ignore index。

比方说下边这个查询:

mysql> EXPLAIN SELECT * FROM t1 WHERE key1 > 'z' AND key2 = 'a';

5b22e89e36e45d70b730dd558856fc4e.png

上述执行计划的possible_keys列的值是idx_key1,idx_key2_key3,表示该查询可能使用到idx_key1,idx_key2_key3两个索引,然后key列的值是idx_key3,表示经过查询优化器计算使用不同索引的成本后,最后决定使用idx_key3来执行查询比较划算。

需要注意的一点是,possible_keys列中的值并不是越多越好,可能使用的索引越多,查询优化器计算查询成本时就得花费更长时间,所以如果可以的话,尽量删除那些用不到的索引。

key_len列

这一列显示了mysql在索引里使用的字节数,通过这个值可以算出具体使用了索引中的哪些列

对于使用固定长度类型的索引列来说,它实际占用的存储空间的最大长度就是该固定值,对于指定字符集的变长类型的索引列来说,比如某个索引列的类型是VARCHAR(100),使用的字符集是utf8,那么该列实际占用的最大存储空间就是100 × 3 = 300个字节。

如果该索引列可以存储NULL值,则key_len比不可以存储NULL值时多1个字节。

对于变长字段来说,都会有2个字节的空间来存储该变长列的实际长度。

当字符串过长时,mysql会做一个类似左前缀索引的处理,将前半部分的字符提取出来做索引。

key_len计算规则如下:字符串 char(n):n字节长度 varchar(n):2字节存储字符串长度,如果是utf-8,则长度 3n + 2 数值类型 tinyint:1字节 smallint:2字节 int:4字节 bigint:8字节   时间类型  date:3字节 timestamp:4字节 datetime:8字节

比如下边这个查询:

mysql> EXPLAIN SELECT * FROM s1 WHERE id = 5;

19dcadaf51ff1fd197ed171c41c0af1d.png

由于id列的类型是INT,并且不可以存储NULL值,所以在使用该列的索引时key_len大小就是4。

对于可变长度的索引列来说,比如下边这个查询:

mysql> EXPLAIN SELECT * FROM t1 WHERE key1 = 'a';

714c1ee18b0510b0ea3fea5550e230d5.png

由于key1列的类型是VARCHAR(100),所以该列实际最多占用的存储空间就是300字节,又因为该列允许存储NULL值,所以key_len需要加1,又因为该列是可变长度列,所以key_len需要加2,所以最后ken_len的值就是303。

rows列

这一列是mysql估计要读取并检测的行数,注意这个不是结果集里的行数。

如果查询优化器决定使用全表扫描的方式对某个表执行查询时,执行计划的rows列就代表预计需要扫描的行数,如果使用索引来执行查询时,执行计划的rows列就代表预计扫描的索引记录行数。比如下边这个查询:

mysql> EXPLAIN SELECT * FROM t1 WHERE key1 > 'a';

792de795546050ec81ae36e3d61b6c4d.png

我们看到执行计划的rows列的值是113,这意味着查询优化器在经过分析使用idx_key1进行查询的成本之后,觉得满足key1 > 'a'这个条件的记录只有113条。

ref列

这一列显示了在key列记录的索引中,表查找值所用到的列或常量,常见的有:const(常量),字段名(例:t1.id)

ref列展示的就是与索引列作等值匹配的值什么,比如只是一个常数或者是某个列。大家看下边这个查询:

mysql> EXPLAIN SELECT * FROM t1 WHERE key1 = 'a';

06a164a9c6a46c90b656c8eabdd358cb.png

可以看到ref列的值是const,表明在使用idx_key1索引执行查询时,与key1列作等值匹配的对象是一个常数,当然有时候更复杂一点:

mysql> EXPLAIN SELECT * FROM t1 INNER JOIN t2 ON t1.id = t2.id;

ccdcf27e5497a9646c80378188a569a7.png

可以看到对被驱动表t1的访问方法是eq_ref,而对应的ref列的值是canal_manager.t2.id,这说明在对被驱动表进行访问时会用到PRIMARY索引,也就是聚簇索引与一个列进行等值匹配的条件,于t2表的id作等值匹配的对象就是canal_manager.t2.id列(注意这里把数据库名也写出来了)。

有的时候与索引列进行等值匹配的对象是一个函数,比方说下边这个查询

mysql> EXPLAIN SELECT * FROM t1 INNER JOIN t2 ON t2.key1 = UPPER(t1.key1);

1f3315ccb4764d8750aedb998d482c58.png

我们看执行计划的第二条记录,可以看到对t2表采用ref访问方法执行查询,然后在查询计划的ref列里输出的是func,说明与t2表的key1列进行等值匹配的对象是一个函数。

Extra列

顾名思义,Extra列是用来说明一些额外信息的,我们可以通过这些额外信息来更准确的理解MySQL到底将如何执行给定的查询语句。

Using index

查询的列被索引覆盖,并且where筛选条件是索引的前导列,是性能高的表现。一般是使用了覆盖索引(索引包含了所有查询的字段)。对于innodb来说,如果是辅助索引性能会有不少提高

mysql> EXPLAIN SELECT key1 FROM t1 WHERE key1 = 'a';

Using where

当我们使用全表扫描来执行对某个表的查询,并且该语句的WHERE子句中有针对该表的搜索条件时,在Extra列中会提示上述额外信息。比如下边这个查询

mysql> EXPLAIN SELECT * FROM t1 WHERE name= 'a1b6cee57a';

ef6e5b1bc0ecb8bf113d35447905817c.png

Using where Using index

查询的列被索引覆盖,并且where筛选条件是索引列之一但是不是索引的前导列,意味着无法直接通过索引查找来查询到符合条件的数据

mysql> EXPLAIN SELECT id FROM t1 WHERE key3= 'a1b6cee57a';

21a2419f8476e3888e1a3c7eedb2f6a5.png

NULL

查询的列未被索引覆盖,并且where筛选条件是索引的前导列,意味着用到了索引,但是部分字段未被索引覆盖,必须通过“回表”来实现,不是纯粹地用到了索引,也不是完全没用到索引

mysql> EXPLAIN SELECT * FROM t1 WHERE key2= 'a1b6cee57a';

164d5ccd32d1ade0a26128944ebe2b0b.png

Using index condition

与Using where类似,查询的列不完全被索引覆盖,where条件中是一个前导列的范围;

mysql>  EXPLAIN SELECT * FROM t1 WHERE key1 like '1';

9ff98d537a5f161996f642612711a6e5.png

Using temporary

在许多查询的执行过程中,MySQL可能会借助临时表来完成一些功能,比如去重、排序之类的,比如我们在执行许多包含DISTINCT、GROUP BY、UNION等子句的查询过程中,如果不能有效利用索引来完成查询,MySQL很有可能寻求通过建立内部的临时表来执行查询。如果查询中使用到了内部的临时表,在执行计划的Extra列将会显示Using temporary提示,比方说这样:

name没有索引,此时创建了张临时表来distinct

mysql> explain select distinct name from t1;

1f5141916665312c70370f73f772e5bb.png

key1建立了idx_key1索引,此时查询时extra是using index,没有用临时表

mysql> explain select distinct key1 from t1;

93647ebd1088a35e665fd613f646d167.png

Using filesort

mysql 会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。此时mysql会根据联接类型浏览所有符合条件的记录,并保存排序关键字和行指针,然后排序关键字并按顺序检索行信息。这种情况下一般也是要考虑使用索引来优化的。

name未创建索引,会浏览t1整个表,保存排序关键字name和对应的id,然后排序name并检索行记录

mysql> explain select * from t1 order by name;

0520008d6fc403154cb51e35fcbe00ea.png

key1建立了idx_key1索引,此时查询时extra是using index

mysql> explain select * from t1 order by key1;

Using join buffer (Block Nested Loop)

在连接查询执行过程中,当被驱动表不能有效的利用索引加快访问速度,MySQL一般会为其分配一块名叫join buffer的内存块来加快查询速度,也就是我们所讲的基于块的嵌套循环算法,比如下边这个查询语句:

mysql> EXPLAIN SELECT * FROM t1 INNER JOIN t2 ON t1.key3 = t2.key3;

02db4d60fdc3210cf8d855c9ad8a0077.png

No tables used

当查询语句的没有FROM子句时将会提示该额外信息,比如:

mysql> EXPLAIN SELECT 1;

53d237cfcb07b516942794fa4dd8262a.png

Impossible WHERE

查询语句的WHERE子句永远为FALSE时将会提示该额外信息,比方说:

mysql> EXPLAIN SELECT * FROM t1 WHERE 1 != 1;

3aaf447232aa70a717f36cf763a015e6.png

参考:

https://dev.mysql.com/doc/refman/5.7/en/explain-output.html#explain-extra-information

往期推荐

前瞻:在 Java 16 中会带来哪些新特性?

高可用 Prometheus 的常见问题

Fastjson <1.2.68版本反序列化漏洞分析篇

音效摸鱼还不够爽&#xff1f;试试IDE里打几盘魂斗罗&#xff1f;

一个让你敲代码的同时&#xff0c;找回童年乐趣的 IntelliJ 插件

扫一扫&#xff0c;关注我

一起学习&#xff0c;一起进步

每周赠书&#xff0c;福利不断

8765ecd5c68982ee046d45d043ebb7b1.png

深度内容

推荐加入

99ebf085659de8e2148ded88d0d77607.png

最近热门内容回顾   #技术人系列

fbbc9ddad3279a6b46a7deabe75cab01.png




推荐阅读
  • MySQL:不仅仅是数据库那么简单
    MySQL不仅是一款高效、可靠的数据库管理系统,它还具备丰富的功能和扩展性,支持多种存储引擎,适用于各种应用场景。从简单的网站开发到复杂的企业级应用,MySQL都能提供强大的数据管理和优化能力,满足不同用户的需求。其开源特性也促进了社区的活跃发展,为技术进步提供了持续动力。 ... [详细]
  • SQLite数据库CRUD操作实例分析与应用
    本文通过分析和实例演示了SQLite数据库中的CRUD(创建、读取、更新和删除)操作,详细介绍了如何在Java环境中使用Person实体类进行数据库操作。文章首先阐述了SQLite数据库的基本概念及其在移动应用开发中的重要性,然后通过具体的代码示例,逐步展示了如何实现对Person实体类的增删改查功能。此外,还讨论了常见错误及其解决方法,为开发者提供了实用的参考和指导。 ... [详细]
  • 本文介绍了UUID(通用唯一标识符)的概念及其在JavaScript中生成Java兼容UUID的代码实现与优化技巧。UUID是一个128位的唯一标识符,广泛应用于分布式系统中以确保唯一性。文章详细探讨了如何利用JavaScript生成符合Java标准的UUID,并提供了多种优化方法,以提高生成效率和兼容性。 ... [详细]
  • MySQL索引详解及其优化策略
    本文详细解析了MySQL索引的概念、数据结构及管理方法,并探讨了如何正确使用索引以提升查询性能。文章还深入讲解了联合索引与覆盖索引的应用场景,以及它们在优化数据库性能中的重要作用。此外,通过实例分析,进一步阐述了索引在高读写比系统中的必要性和优势。 ... [详细]
  • 本文详细介绍了在 SQL Server 2005 中优化和实现分页存储过程的方法。通过创建一个名为 `[dbo].[GetUsers]` 的存储过程,该过程接受两个参数:`@RowIndex`(当前指定的页数)和 `@RecordCount`(每页显示的记录数)。文章不仅提供了具体的代码示例,还深入探讨了性能优化技巧,包括索引使用和查询优化策略,以提高分页查询的效率和响应速度。 ... [详细]
  • 本文深入解析了Python在处理HTML过滤时的实现方法及其应用场景。通过具体实例,详细介绍了如何利用Python代码去除HTML字符串中的标签和其他无关信息,确保内容的纯净与安全。此外,文章还探讨了该技术在网页抓取、数据清洗等领域的实际应用,为开发者提供了宝贵的参考。 ... [详细]
  • 本文深入探讨了CGLIB BeanCopier在Bean对象复制中的应用及其优化技巧。相较于Spring的BeanUtils和Apache的BeanUtils,CGLIB BeanCopier在性能上具有显著优势。通过详细分析其内部机制和使用场景,本文提供了多种优化方法,帮助开发者在实际项目中更高效地利用这一工具。此外,文章还讨论了CGLIB BeanCopier在复杂对象结构和大规模数据处理中的表现,为读者提供了实用的参考和建议。 ... [详细]
  • 在数据表中,我需要触发一个操作来刷新特定列的数据。例如,对于以下表格:| ID | Name | IsDeleted ||----|-------|-----------|| 1 | test | True || 2 | test2 | False |我希望在点击“更新”按钮时,能够仅刷新选定行的“IsDeleted”列。这将有助于确保数据的实时性和准确性。 ... [详细]
  • 本文深入探讨了 HTML 中的 `margin` 属性,详细解析了其基本特性和应用场景。文章不仅介绍了 `margin` 的基本概念,还重点讨论了垂直外边距合并现象,并分析了 `margin` 在块级元素与内联元素中的不同表现。通过实例和代码示例,帮助读者全面理解 `margin` 的使用技巧和常见问题。 ... [详细]
  • 哈希表(Hash Table)是一种高效的查找算法,与传统的链表和树结构相比,其在查找过程中无需进行逐个元素的比较。本文将深入探讨哈希表的基本原理、应用场景以及优化策略,帮助读者全面理解其在实际开发中的优势和局限性。通过实例分析和代码示例,我们将展示如何有效利用哈希表提高数据处理效率,并解决常见的冲突问题。 ... [详细]
  • 在过去,我曾使用过自建MySQL服务器中的MyISAM和InnoDB存储引擎(也曾尝试过Memory引擎)。今年初,我开始转向阿里云的关系型数据库服务,并深入研究了其高效的压缩存储引擎TokuDB。TokuDB在数据压缩和处理大规模数据集方面表现出色,显著提升了存储效率和查询性能。通过实际应用,我发现TokuDB不仅能够有效减少存储成本,还能显著提高数据处理速度,特别适用于高并发和大数据量的场景。 ... [详细]
  • 在使用 `useSelector` 选择器时,发现分派操作后状态未能实时更新。这可能是由于 React 组件的渲染机制或 Redux 的状态管理问题导致的。建议检查 `useSelector` 的依赖项和 `dispatch` 的调用时机,确保状态变化能够正确触发组件重新渲染。此外,可以考虑使用 `useEffect` 钩子来监听状态变化,以确保及时更新。 ... [详细]
  • 在MySQL中实现时间比较功能的详细解析与应用
    在MySQL中实现时间比较功能的详细解析与应用。本文深入探讨了MySQL中时间比较的实现方法,重点介绍了`UNIX_TIMESTAMP`函数的应用。该函数可以接收一个日期时间参数,也可以不带参数使用,其返回值为Unix时间戳,便于进行时间的精确比较和计算。此外,文章还涵盖了其他相关的时间处理函数和技巧,帮助读者更好地理解和掌握MySQL中的时间操作。 ... [详细]
  • 在 Windows 10 环境中,通过配置 Visual Studio Code (VSCode) 实现基于 Windows Subsystem for Linux (WSL) 的 C++ 开发,并启用智能代码提示功能。具体步骤包括安装 VSCode 及其相关插件,如 CCIntelliSense、TabNine 和 BracketPairColorizer,确保在 WSL 中顺利进行开发工作。此外,还详细介绍了如何在 Windows 10 中启用和配置 WSL,以实现无缝的跨平台开发体验。 ... [详细]
  • Jedis接口分类详解与应用指南
    本文详细解析了Jedis接口的分类及其应用指南,重点介绍了字符串数据类型(String)的接口功能。作为Redis中最基本的数据存储形式,字符串类型支持多种操作,如设置、获取和更新键值对等,适用于广泛的应用场景。 ... [详细]
author-avatar
手机用户2602936475
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有