京东6.18大促主会场领京享红包更优惠

 找回密码
 立即注册

QQ登录

只需一步,快速开始

MySQL中EXPLAIN的/基本使用及字段详解

2024-11-2 22:43| 发布者: 284cc| 查看: 51| 评论: 0

摘要: 目次一、先容二、基本的使用三、字段详解3.1、id字段3.2、select_type 与 table字段3.3、partitions3.4、type字段3.5、possible_keys 与 key字段3.6、key_len字段3.7、ref 字段3.8、rows 字段3.9、filtered 字段3.9
目次

一、先容

官网先容:

[code]https://dev.mysql.com/doc/refman/5.7/en/explain-output.html https://dev.mysql.com/doc/refman/8.0/en/explain-output.html[/code]

explain(实行计划),使用explain关键字可以模仿优化器实行sql查询语句,从而知道MySQL是怎样处理sql语句。

explain主要用于分析查询语句或表布局的性能瓶颈。

通过explain命令可以得到:

  • – 表的读取顺序
  • – 数据读取操作的操作类型
  • – 哪些索引可以使用
  • – 哪些索引被现实使用
  • – 表之间的引用
  • – 每张表有多少行被优化器查询

EXPLAIN 或者 DESC命令获取 MySQL 怎样实行 SELECT 语句的信息,包括在 SELECT 语句实行过程中表怎样连接和连接的顺序。

版本环境

  • MySQL 5.6.3从前只能EXPLAIN SELECT ;MYSQL 5.6.3以后就可以EXPLAIN SELECT,UPDATE,DELETE
  • 在5.7从前的版本中,想要显示partitions 必要使用explain partitions 命令;想要显示filtered 必要使用explain extended 命令。在5.7版本后,默认explain直接显示partitions和filtered中的信息。

基本语法

EXPLAIN 或 DESCRIBE语句的语法形式如下:

[code]EXPLAIN SELECT select_options [/code]

或者

[code]DESCRIBE SELECT select_options [/code]

环境准备:

[code]CREATE DATABASE testexplain CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; [/code] [code]use testexplain; [/code] [code]CREATE TABLE L1(id INT PRIMARY KEY AUTO_INCREMENT,title VARCHAR(100) ); CREATE TABLE L2(id INT PRIMARY KEY AUTO_INCREMENT,title VARCHAR(100) ); CREATE TABLE L3(id INT PRIMARY KEY AUTO_INCREMENT,title VARCHAR(100) ); CREATE TABLE L4(id INT PRIMARY KEY AUTO_INCREMENT,title VARCHAR(100) ); [/code] [code]INSERT INTO L1(title) VALUES('test001'),('test002'),('test003'); INSERT INTO L2(title) VALUES('test004'),('test005'),('test006'); INSERT INTO L3(title) VALUES('test007'),('test008'),('test009'); INSERT INTO L4(title) VALUES('test010'),('test011'),('test012'); [/code]

二、基本的使用

explain使用:explain/desc+sql语句,通过实行explain可以得到sql语句实行的相关信息。

[code]EXPLAIN SELECT * FROM L1,L2,L3 WHERE L1.id=L2.id AND L2.id = L3.id; [/code] [code]DESC SELECT * FROM L1,L2,L3 WHERE L1.id=L2.id AND L2.id = L3.id; [/code]

序号字段含义
1id查询的序列号,是一组数字,表示查询中实行 [code]SELECT[/code] 子句或操作表的顺序。
2select_type表示 [code]SELECT[/code] 的类型。常见取值有 [code]SIMPLE[/code](简朴查询,不包罗子查询或联合查询)、[code]PRIMARY[/code](主查询,即最外层的查询)、[code]UNION[/code](联合查询中的第二个或后续查询)、[code]SUBQUERY[/code](子查询)等。
3table表示正在访问的表。
4partitions显示匹配的分区信息,假如是非分区表则为 [code]NULL[/code]。
5type表示表的访问类型,性能由好到差的顺序为 [code]system[/code] → [code]const[/code] → [code]eq_ref[/code] → [code]ref[/code] → [code]ref_or_null[/code] → [code]index_merge[/code] → [code]unique_subquery[/code] → [code]index_subquery[/code] → [code]range[/code] → [code]index[/code] → [code]ALL[/code]。访问类型越靠前,性能越好。
6possible_keys表示查询时大概使用的索引。
7key现实使用的索引。假如没有使用索引,则显示为 [code]NULL[/code]。
8key_len表示使用的索引的字节数。这个值越大,表示查询中使用的索引字段越多。
9ref显示索引的哪一列被用到,并且假如大概的话,是哪些列或常量被用于查找索引列中的值。
10rows估计要读取的行数,这个数字是一个估计值,不肯定是准确的。
11filtered表示服务器根据查询条件过滤的行百分比。
12Extra包罗实行查询的额外信息,比如是否使用临时表、是否举行文件排序等。常见值有 [code]Using index[/code](使用了覆盖索引)、[code]Using where[/code](使用了 [code]WHERE[/code] 过滤条件)、[code]Using temporary[/code](使用了临时表)和 [code]Using filesort[/code](使用了文件排序)等。

三、字段详解

3.1、id字段

select查询的序列号,包罗一组数字,表示查询中实行select子句或操作表的顺序

  • id雷同,实行顺序由上至下
[code]EXPLAIN SELECT * FROM L1,L2,L3 WHERE L1.id=L2.id AND L2.id = L3.id; [/code]

  • id差别,假如是子查询,id的序号会递增,id值越大优先级越高,越先被实行
[code]EXPLAIN SELECT * FROM L2 WHERE id = (SELECT id FROM L1 WHERE id = (SELECT L3.id FROM L3 WHERE L3.title = 'test009')); [/code]

3.2、select_type 与 table字段

查询类型,主要用于区别普通查询,联合查询,子查询等的复杂查询

  • simple : 简朴的select查询,查询中不包罗子查询或者UNION
[code]EXPLAIN SELECT * FROM L1; [/code]

  • primary : 查询中若包罗任何复杂的子部分,最外层查询被标记
[code]EXPLAIN SELECT * FROM L2 WHERE id = (SELECT id FROM L1 WHERE id = (SELECT L3.id FROM L3 WHERE L3.title = 'test003')); [/code]

  • subquery : 在select或where列表中包罗了子查询
[code]EXPLAIN SELECT * FROM L2 WHERE L2.id = (SELECT id FROM L3 WHERE L3.title = 'test03'); [/code]

  • derived : 在from列表中包罗的子查询被标记为derived(衍生),MySQL会递归实行这些子查询,把效果放到临时表中
  • union : 假如第二个select出现在UNION之后,则被标记为UNION,假如union包罗在from子句的子查询中,外层select被标记为derived
  • union result : UNION 的效果
[code]EXPLAIN SELECT * FROM L2 UNION SELECT * FROM L3; [/code]

3.3、partitions

分区表是将一个表的数据根据某个字段的值分成多个分区来存储的,如许查询时可以进步服从。

查询时匹配到的分区信息,对于非分区表值为NULL ,当查询的是分区表时, partitions 显示分区表命中的分区环境。

对于非分区表(例如原始的 [code]L1[/code] 表),[code]partitions[/code] 字段会显示 [code]NULL[/code]:

[code]EXPLAIN SELECT * FROM L1 WHERE id = 1; [/code]

我们以 [code]L1[/code] 表为例,将它根据 [code]id[/code] 字段举行分区:

[code]CREATE TABLE L1_partitioned ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(100) ) PARTITION BY RANGE (id) ( PARTITION p0 VALUES LESS THAN (2), PARTITION p1 VALUES LESS THAN (4), PARTITION p2 VALUES LESS THAN (6) ); [/code] [code]INSERT INTO L1_partitioned(title) VALUES('test001'),('test002'),('test003'),('test004'),('test005'); [/code]

这个表会根据 [code]id[/code] 的值分成 3 个分区:

  • [code]p0[/code] 分区存储 [code]id[/code] 小于 2 的数据
  • [code]p1[/code] 分区存储 [code]id[/code] 小于 4 的数据
  • [code]p2[/code] 分区存储 [code]id[/code] 小于 6 的数据

使用 [code]EXPLAIN[/code] 检察查询的分区命中环境:

[code]EXPLAIN SELECT * FROM L1_partitioned WHERE id = 1; [/code]

此查询会显示 [code]partitions[/code] 字段的值为 [code]p0[/code],由于 [code]id=1[/code] 的记载被存储在 [code]p0[/code] 分区中。

[code]EXPLAIN SELECT * FROM L1_partitioned WHERE id = 3; [/code]

此查询会显示 [code]partitions[/code] 字段的值为 [code]p1[/code],由于 [code]id=3[/code] 的记载被存储在 [code]p1[/code] 分区中。

当查询条件跨越多个分区时,[code]EXPLAIN[/code] 会显示命中的多个分区:

[code]EXPLAIN SELECT * FROM L1_partitioned WHERE id BETWEEN 1 AND 5; [/code]

3.4、type字段

type显示的是连接类型,是较为告急的一个指标。下面给出各种连接类型,按照从最佳类型到最坏类型举行排序:

[code]system > const > eq_ref > ref > fulltext > ref_or_null > index_merge >unique_subquery > index_subquery > range > index > ALL [/code] [code]-- 简化 system > const > eq_ref > ref > range > index > ALL [/code]
  • system : 表仅有一行 (等于体系表)。这是const连接类型的一个特例,很少出现。
  • const : 表示通过索引 一次就找到了, const用于比较 primary key 或者 unique 索引. 由于只匹配一行数据,所以假如将主键 放在 where条件中, MySQL就能将该查询转换为一个常量
[code]EXPLAIN SELECT * FROM L1 WHERE L1.id = 1; [/code]

  • eq_ref : 唯一性索引扫描,对于每个索引键,表中只有一条记载与之匹配. 常见与主键或唯一索引扫描
[code]EXPLAIN SELECT * FROM L1 ,L2 WHERE L1.id = L2.id ; [/code]

  • ref : 非唯一性索引扫描, 返回匹配某个单独值的所有行, 本质上也是一种索引访问, 它返回所有匹配某个单独值的行, 这是比较常见连接类型.

    • 未加索引之前

      [code]EXPLAIN SELECT * FROM L1 ,L2 WHERE L1.title = L2.title ; [/code]

    • 加索引之后

      [code]CREATE INDEX idx_title ON L2(title); [/code] [code]EXPLAIN SELECT * FROM L1 ,L2 WHERE L1.title = L2.title ; [/code]

  • range : 只检索给定范围的行,使用一个索引来选择行。

    [code]EXPLAIN SELECT * FROM L1 WHERE L1.id > 10; [/code] [code]EXPLAIN SELECT * FROM L1 WHERE L1.id IN (1,2); [/code]

    key显示使用了哪个索引. where 子句背面 使用 between 、< 、> 、in 等查询, 这种范围查询要比全表扫描好

  • index : 出现index 是 SQL 使用了索引, 但是没有通过索引举行过滤,一般是使用了索引举行排序分组

[code]EXPLAIN SELECT * FROM L1 ORDER BY id; [/code]

  • ALL : 对于每个来自于先前的表的行组合,举行完备的表扫描。
[code]EXPLAIN SELECT * FROM L1; [/code]

[code]一般来说,必要包管查询至少达到 range级别,最好能到ref[/code]

3.5、possible_keys 与 key字段

  • possible_keys
    • 显示大概应用到这张表上的索引, 一个或者多个. 查询涉及到的字段上若存在索引, 则该索引将被列出, 但不肯定被查询现实使用.
    • 现实使用的索引,若为null,则没有使用到索引。(两种大概,1.没创建索引, 2.创建索引,但索引失效)。查询中若使用了覆盖索引,则该索引仅出现在key列表中。
  • key
    • 现实使用的索引,若为null,则没有使用到索引。(两种大概,1.没创建索引, 2.创建索引,但索引失效)。查询中若使用了覆盖索引,则该索引仅出现在key列表中。
    • 覆盖索引:一个索引包罗(或覆盖)所有必要查询的字段的值,通过查询索引就可以获取到字段值
  • 理论上没有使用索引,但现实上使用了
[code]EXPLAIN SELECT L1.id FROM L1; [/code]

  • 理论和现实上都没有使用索引
[code]EXPLAIN SELECT * FROM L1 WHERE title = 'test01'; [/code]

  • 理论和现实上都使用了索引
[code]EXPLAIN SELECT * FROM L2 WHERE title = 'test02'; [/code]

3.6、key_len字段

表示索引中使用的字节数, 可以通过该列盘算查询中使用索引的长度.

key_len 字段能够帮你查抄是否充实使用了索引 ken_len 越长, 分析索引使用的越充实

key_len表示使用的索引长度,key_len可以衡量索引的优劣,key_len越小 索引效果越好

[code]上述的这两句话是否存在矛盾呢,我们该怎么明确呢? 第一句:[code]key_len[/code] 越长,分析索引使用得越充实 表明
  • [code]key_len[/code] 表示在查询中使用的索引字节数。它反映了查询条件中现实使用了索引的多少。
  • 例如,假设有一个复合索引(例如 [code]index_a_b_c[/code]),它包罗三个字段 [code]a, b, c[/code]。假如你实行的查询只使用了 [code]a[/code] 字段举行筛选,那么 [code]key_len[/code] 大概只包罗字段 [code]a[/code] 的长度。假如查询使用了 [code]a[/code] 和 [code]b[/code] 两个字段举行筛选,[code]key_len[/code] 会增加,以反映更多的索引字段被使用。
  • 因此,当 [code]key_len[/code] 较长时,意味着查询充实使用了索引的多个部分,这通常可以进步查询服从。
第二句:[code]key_len[/code] 越小,索引效果越好 表明
  • 这句话夸大了索引的选择性和服从。[code]key_len[/code] 越小,表示查询使用的索引部分越少,也大概意味着查询的目的更加精准,过滤的行数越少。
  • 假如一个查询只需使用索引的前几列(即 [code]key_len[/code] 较小),并且可以快速过滤掉大部分不相关的行,那么该查询的服从通常会更高。
  • 在某些环境下,使用较小的 [code]key_len[/code] 大概会比使用较大的 [code]key_len[/code] 更有效,由于这减少了不须要的索引扫描(特殊是当大部分行都匹配前面的字段时)。
怎样综合明确这两句话 这两句话并不矛盾,而是从差别的角度表明了 [code]key_len[/code] 的作用: 充实使用索引:当你盼望尽大概使用复合索引的多个字段时,较大的 [code]key_len[/code] 是有利的,由于它表明查询条件使用了索引的多个部分,从而大概减少全表扫描的需求。 索引的服从:另一方面,较小的 [code]key_len[/code] 大概意味着查询条件已经足够过滤掉大多数不匹配的行,从而更快地找到所需的记载。 现实应用中的考量
  • 复合索引:假如你的查询常常使用复合索引的前几个字段,而不使用全部字段,那么你大概盼望 [code]key_len[/code] 较小,如许查询服从大概更高,由于数据库引擎不必要扫描索引的所有部分。
  • 单字段索引:假如你有一个单字段索引,那么 [code]key_len[/code] 的大小主要取决于这个字段的类型。对于简朴的查询,[code]key_len[/code] 较小大概是好事。
总结来说,[code]key_len[/code] 并不是越大或越小越好,而是要根据查询的详细环境来衡量。当 [code]key_len[/code] 充实使用了索引的关键字段,并且有效过滤数据时,这通常是一个高效的查询计划。[/code] [code]SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` bigint NOT NULL AUTO_INCREMENT, `name` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `age` int NULL DEFAULT NULL, `sex` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `create_time` datetime NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE, INDEX `idx_name`(`name` ASC) USING BTREE, INDEX `idx_age`(`age` ASC) USING BTREE, INDEX `idx_sex`(`sex` ASC) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; INSERT INTO `user` VALUES (1, 'tom', 18, '男', '2024-08-17 10:09:00'); INSERT INTO `user` VALUES (2, 'zimu', 18, '男', '2024-08-07 10:09:30'); [/code]
  • 使用explain 举行测试
列类型是否为空长度key_len备注
tinyint答应Null1key_len = 1 + 1答应NULL,key_len长度加1
tinyint not null不答应Null1key_len = 1不答应NULL
int答应Null4key_len = 4 + 1答应NULL,key_len长度加1
int not null不答应Null4key_len = 4不答应NULL
bigint答应Null8key_len = 8 + 1答应NULL,key_len长度加1
bigint not null不答应Null8key_len = 8不答应NULL
char(1)答应Nullutf8mb4=4, utf8=3, gbk=2key_len = 1*3 + 1答应NULL,字符集utf8,key_len长度加1
char(1) not null不答应Nullutf8mb4=4, utf8=3, gbk=2key_len = 1*3不答应NULL,字符集utf8
varchar(10)答应Nullutf8mb4=4, utf8=3, gbk=2key_len = 10*3 + 2 + 1动态列类型,key_len长度加2,答应NULL,key_len长度加1
varchar(10) not null不答应Nullutf8mb4=4, utf8=3, gbk=2key_len = 10*3 + 2动态列类型,key_len长度加2
  • id字段类型为bigint,长度为8,id为主键,不答应Null ,key_len = 8 。

    [code]EXPLAIN select * FROM user WHERE id = 1; [/code]

  • name的字段类型是varchar(10),答应Null,字符编码是utf8,一个字符占用3个字节,varchar为动态类型,key长度加2,key_len = 10 * 3 + 2 + 1 = 33 。
[code]EXPLAIN select * FROM user WHERE name = 'tom'; [/code]

联合索引key_len盘算

我们删除user表其他辅助索引,创建一个联合索引

[code]ALTER TABLE user DROP INDEX `idx_name`, DROP INDEX `idx_age`, DROP INDEX `idx_sex`; [/code] [code]ALTER TABLE user ADD INDEX `idx_name_age`(`name`, `age`); [/code]

1、部分索引生效的环境

我们使用name举行查询

[code]EXPLAIN select * FROM user WHERE name = 'tom'; [/code]

由于联合索引,根据最左匹配原则,使用到索引只有name这一列,name的字段类型是varchar(10),答应Null,字符编码是utf8,一个字符占用3个字节,varchar为动态类型,key长度加2,key_len = 10 * 3+2 + 1 = 33 。

2、联合索引完全使用索引的环境

[code]EXPLAIN select * FROM user WHERE name = '张三' AND age = 19; [/code]

由于联合索引,使用到(name,age)联合索引,name的字段类型是varchar(10),答应Null,字符编码是utf8,一个字符占用3个字节,varchar为动态类型,key长度加2,key_len = 10 * 3 + 2 + 1 = 33 ,age的字段类型是int,长度为4,答应Null ,key_len = 4 + 1 = 5 。联合索引的key_len 为 key_len = 33+5 = 38。

3.7、ref 字段

显示索引的哪一列被使用了,假如大概的话,是一个常数。哪些列或常量被用于查找索引列上的值

  • L1.id=‘1’; 1是常量 , ref = const
[code]EXPLAIN SELECT * FROM L1 WHERE L1.id='1'; [/code]

  • L2表被关联查询的时间,使用了主键索引, 而值使用的是驱动表(实行计划中靠前的表是驱动表)L1表的ID, 所以 ref = test_explain.L1.id
[code]EXPLAIN SELECT * FROM L1 LEFT JOIN L2 ON L1.id = L2.id WHERE L1.title ='test01'; [/code]

[code]什么是驱动表 ?
  • 多表关联查询时,第一个被处理的表就是驱动表,使用驱动表去关联其他表.
  • 驱动表简直定非常的关键,会直接影响多表关联的顺序,也决定后续关联查询的性能
驱动表的选择要遵循一个规则: 在对最终的效果集没有影响的前提下,优先选择效果集最小的那张表作为驱动表[/code]

3.8、rows 字段

表示MySQL根据表统计信息及索引选用环境,估算的找到所需的记载所必要读取的行数;越少越好

  • 使用like 查询,会产生全表扫描, L2中有3条记载,就必要读取3条记载举行查找
[code]EXPLAIN SELECT * FROM L1,L2 WHERE L1.id = L2.id AND L2.title LIKE '%tes%'; [/code]

  • 假如使用等值查询, 则可以直接找到要查询的记载,返回即可,所以只必要读取一条
[code]EXPLAIN SELECT * FROM L1,L2 WHERE L1.id = L2.id AND L2.title = 'test03'; [/code]

总结: 当我们必要优化一个SQL语句的时间,我们必要知道该SQL的实行计划,比如是全表扫描,照旧索引扫描; 使用explain 关键字可以模仿优化器实行sql 语句,从而知道mysql 是怎样处理sql 语句的,方便我们开发职员有针对性的对SQL举行优化.

  • 表的读取顺序。(对应id)

  • 数据读取操作的操作类型。(对应select_type)

  • 哪些索引可以使用。(对应possible_keys)

  • 哪些索引被现实使用。(对应key)

  • 每张表有多少行被优化器查询。(对应rows)

  • 评估sql的质量与服从 (对应type)

3.9、filtered 字段

它指返回效果的行占必要读到的行(rows列的值)的百分比

3.9、extra 字段

Extra 是 EXPLAIN 输出中别的一个很告急的列,该列显示MySQL在查询过程中的一些详细信息

[code]CREATE TABLE users ( uid INT PRIMARY KEY AUTO_INCREMENT, uname VARCHAR(20), age INT(11) ); INSERT INTO users VALUES(NULL, 'lisa',10); INSERT INTO users VALUES(NULL, 'lisa',10); INSERT INTO users VALUES(NULL, 'rose',11); INSERT INTO users VALUES(NULL, 'jack', 12); INSERT INTO users VALUES(NULL, 'sam', 13); [/code]
  • Using filesort
[code]EXPLAIN SELECT * FROM users ORDER BY age; [/code]

实行效果Extra为Using filesort ,这分析,得到所需效果集,必要对所有记载举行文件排序。这类SQL语句性能极差,必要举行优化。

典型的,在一个没有创建索引的列上举行了order by,就会触发filesort,常见的优化方案是,在order by的列上添加索引,克制每次查询都全量排序。

filtered 它指返回效果的行占必要读到的行(rows列的值)的百分比

  • Using temporary
[code]EXPLAIN SELECT COUNT(*),uname FROM users WHERE uid > 2 GROUP BY uname; [/code]

实行效果Extra为Using temporary ,这分析必要创建临时表 (temporary table) 来暂存中央效果。性能消耗大, 必要创建一张临时表, 常见于group by语句中. 需共同SQL实行过程来表明, 假如group by和where索引条件差别, 那么group by中的字段必要创建临时表分组后再回到原查询表中.假如查询条件where和group by是雷同索引字段, 那么就不必要临时表.

  • Using where
[code]EXPLAIN SELECT * FROM users WHERE age=10; [/code]

此语句的实行效果Extra为Using where,表示使用了where条件过滤数据。必要留意的是:

  • 返回所有记载的SQL,不使用where条件过滤数据,大概率不符合预期,对于这类SQL往往必要举行优化;
  • 使用了where条件的SQL,并不代表不必要优化,往往必要共同explain效果中的type(连接类型)来综合判定。例如本例查询的 age 未设置索引,所以返回的type为ALL,仍有优化空间,可以创建索引优化查询。
  • Using index

表示直接访问索引就能够获取到所必要的数据(覆盖索引) , 不必要通过索引回表.

[code]-- 为uname创建索引 alter table users add index idx_uname(uname); [/code] [code]EXPLAIN SELECT uid,uname FROM users WHERE uname='lisa'; [/code]

此句实行效果为Extra为Using index,分析sql所必要返回的所有列数据均在一棵索引树上,而无需访问现实的行记载。

  • Using join buffer (Block Nested Loop):
    • 这个 [code]Extra[/code] 字段的值表明 MySQL 在实行嵌套循环连接时使用了连接缓冲区。这通常发生在没有可用的合适索引时,MySQL 会将一个表的数据加载到内存中的缓冲区,然后逐一扫描另一个表,以找到满意连接条件的行。
    • Block Nested Loop 是指 MySQL 会将外部表(在本例中是 [code]u1[/code])的部分数据块加载到缓冲区,然后与内部表(在本例中是子查询派生表 [code]u2[/code])举行匹配。如许可以减少对磁盘的访问次数,进步查询服从。

必要举行嵌套循环盘算.

[code]ALTER TABLE users ADD COLUMN sex CHAR(1); [/code] [code]UPDATE users SET sex = '0' WHERE uname IN ('lisa', 'rose'); UPDATE users SET sex = '1' WHERE uname IN ('jack', 'sam'); [/code] [code]EXPLAIN SELECT * FROM users u1 LEFT JOIN (SELECT * FROM users WHERE sex = '0') u2 ON u1.uname = u2.uname; [/code]

没有显示 [code]Using join buffer[/code],大概是由于查询优化器在这个详细的场景下能够有效地使用索引,因此不必要使用连接缓冲区。在这种环境下,MySQL 直接使用了 [code]ref[/code] 类型的连接(通过索引举行连接),而不是必要缓冲区的嵌套循环连接。

可以删除或修改表上的索引,以便让 MySQL 在实行查询时无法使用现有的索引,从而被迫使用连接缓冲区。

[code]ALTER TABLE users DROP INDEX idx_uname; [/code] [code]EXPLAIN SELECT * FROM users u1 LEFT JOIN (SELECT * FROM users WHERE sex = '0') u2 ON u1.uname = u2.uname; [/code]

实行效果Extra为Using join buffer (Block Nested Loop) 分析,必要举行嵌套循环盘算, 这里每个表都有五条记载,内外表查询的type都为ALL。

题目在于 两个关联表join 使用 uname,关联字段均未创建索引,就会出现这种环境。

常见的优化方案是,在关联字段上添加索引,克制每次嵌套循环盘算。

  • Using index condition

搜索条件中固然出现了索引列,但是有部分条件无法使用索引,会根据能用索引的条件先搜索一遍再匹配无法使用索引的条件。

Using index condition 叫作 Index Condition Pushdown Optimization (索引下推优化)。Index Condition Pushdown (ICP)是MySQL使用索引从表中检索行的一种优化。假如没有ICP,存储引擎将遍历索引以定位表中的行,并将它们返回给MySQL服务器,服务器将判定行的WHERE条件。在启用ICP的环境下,假如可以只使用索引中的列来盘算WHERE条件的一部分,MySQL服务器就会将WHERE条件的这一部分推到存储引擎中。然后,存储引擎通过使用索引条目来评估推入的索引条件,只有当满意该条件时,才从表中读取行。ICP可以减少存储引擎必须访问基表的次数和MySQL服务器必须访问存储引擎的次数。

[code]CREATE TABLE employees ( id INT PRIMARY KEY AUTO_INCREMENT, first_name VARCHAR(50), last_name VARCHAR(50), age INT, department_id INT, salary DECIMAL(10, 2), hire_date DATE ); INSERT INTO employees (first_name, last_name, age, department_id, salary, hire_date) VALUES ('John', 'Doe', 30, 1, 60000.00, '2015-03-01'), ('Jane', 'Doe', 28, 2, 65000.00, '2016-07-15'), ('Mike', 'Smith', 45, 3, 75000.00, '2010-10-22'), ('Sara', 'Jones', 32, 1, 55000.00, '2018-01-12'), ('Tom', 'Brown', 29, 2, 58000.00, '2017-05-18'); [/code]

接着,我们在 [code]last_name[/code] 和 [code]age[/code] 字段上创建复合索引:

[code]CREATE INDEX idx_lastname_age ON employees(last_name, age); [/code]

编写一个查询,包罗部分能使用索引的条件和部分不能使用索引的条件:

[code]EXPLAIN SELECT * FROM employees WHERE last_name = 'Doe' AND age > 25 AND salary > 60000; [/code]

这一行表明 MySQL 在查询中使用了 [code]Index Condition Pushdown[/code] 优化。

在这个例子中,[code]last_name = 'Doe'[/code] 和 [code]age > 25[/code] 可以使用复合索引 [code]idx_lastname_age[/code],因此 MySQL 使用索引条件下推技能,在存储引擎层面尽量减少访问行数据的次数。

[code]salary > 60000[/code] 是不能使用索引的条件,但由于使用了 ICP,存储引擎会先根据 [code]last_name[/code] 和 [code]age[/code] 举行初步过滤,然后再把符合条件的行返回给 MySQL 服务器,服务器进一步应用 [code]salary > 60000[/code] 的过滤。

总结:

Index Condition Pushdown (ICP) 是一种优化技能,答应 MySQL 在存储引擎层面应用部分 [code]WHERE[/code] 条件,从而减少必要从表中读取的行数。这可以进步查询性能,尤其是在涉及复合索引时。

[code]Using index condition[/code] 提示表示 MySQL 已经应用了 ICP 优化。通过使用复合索引和带有多条件的查询,可以显式地观察到这个优化技能的作用。

到此这篇关于MySQL中EXPLAIN的/基本使用及字段详解的文章就先容到这了,更多相关MySQL中EXPLAIN详解内容请搜索脚本之家从前的文章或继承浏览下面的相关文章盼望各人以后多多支持脚本之家!


来源:https://www.jb51.net/database/327227wiu.htm
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
关闭

站长推荐上一条 /6 下一条

QQ|手机版|小黑屋|梦想之都-俊月星空 ( 粤ICP备18056059号 )|网站地图

GMT+8, 2025-7-2 08:52 , Processed in 0.043729 second(s), 18 queries .

Powered by Mxzdjyxk! X3.5

© 2001-2025 Discuz! Team.

返回顶部