MySQL中的EXPLAIN的详解

news2024/9/28 23:23:22

一、介绍

官网介绍:

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

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中的信息。

image-20240816220734072

基本语法

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

EXPLAIN SELECT select_options

或者

DESCRIBE SELECT select_options

环境准备:

CREATE DATABASE testexplain  CHARACTER SET utf8mb4   COLLATE utf8mb4_general_ci;
use testexplain;
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) );
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');

image-20240817084735762

二、基本的使用

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

EXPLAIN SELECT * FROM L1,L2,L3 WHERE L1.id=L2.id AND L2.id = L3.id;
DESC SELECT * FROM L1,L2,L3 WHERE L1.id=L2.id AND L2.id = L3.id;

image-20240817084858568

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

三、字段详解

3.1、id字段

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

  • id相同,执行顺序由上至下
EXPLAIN SELECT * FROM L1,L2,L3 WHERE L1.id=L2.id AND L2.id = L3.id;

image-20240817085211653

  • id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
EXPLAIN
SELECT *
FROM L2
WHERE id = (SELECT id
            FROM L1
            WHERE id = (SELECT L3.id
                        FROM L3
                        WHERE L3.title =
                              'test009'));

image-20240817085352563

3.2、select_type 与 table字段

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

  • simple : 简单的select查询,查询中不包含子查询或者UNION
EXPLAIN SELECT * FROM L1;

image-20240817085911835

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

image-20240817090120901

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

image-20240817090310861

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

image-20240817090413483

3.3、partitions

分区表是将一个表的数据根据某个字段的值分成多个分区来存储的,这样查询时可以提高效率。

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

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

EXPLAIN SELECT * FROM L1 WHERE id = 1;

image-20240817090919620

我们以 L1 表为例,将它根据 id 字段进行分区:

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)
);
INSERT INTO L1_partitioned(title) VALUES('test001'),('test002'),('test003'),('test004'),('test005');

这个表会根据 id 的值分成 3 个分区:

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

image-20240817091047683

使用 EXPLAIN 查看查询的分区命中情况:

EXPLAIN SELECT * FROM L1_partitioned WHERE id = 1;

image-20240817091142620

此查询会显示 partitions 字段的值为 p0,因为 id=1 的记录被存储在 p0 分区中。

EXPLAIN SELECT * FROM L1_partitioned WHERE id = 3;

image-20240817091233302

此查询会显示 partitions 字段的值为 p1,因为 id=3 的记录被存储在 p1 分区中。

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

EXPLAIN SELECT * FROM L1_partitioned WHERE id BETWEEN 1 AND 5;

image-20240817091350492

3.4、type字段

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

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

image-20240817091731680

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

image-20240817092051794

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

    • 未加索引之前

      EXPLAIN SELECT * FROM L1 ,L2 WHERE L1.title = L2.title ;
      

      image-20240817092203285

    • 加索引之后

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

      image-20240817092326116

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

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

    image-20240817092525645

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

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

EXPLAIN SELECT * FROM L1 ORDER BY id;

image-20240817092721394

  • ALL : 对于每个来自于先前的表的行组合,进行完整的表扫描。
EXPLAIN SELECT * FROM L1;

image-20240817092820538

一般来说,需要保证查询至少达到 range级别,最好能到ref

3.5、possible_keys 与 key字段

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

image-20240817094243911

  1. 理论和实际上都没有使用索引
EXPLAIN SELECT * FROM L1 WHERE title = 'test01';

image-20240817095248987

  1. 理论和实际上都使用了索引
EXPLAIN SELECT * FROM L2 WHERE title = 'test02';

image-20240817095340019

3.6、key_len字段

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

key_len 字段能够帮你检查是否充分利用了索引 ken_len 越长, 说明索引使用的越充分

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

上述的这两句话是否存在矛盾呢,我们该怎么理解呢?

第一句:key_len 越长,说明索引使用得越充分

解释

  • key_len 表示在查询中使用的索引字节数。它反映了查询条件中实际使用了索引的多少。

  • 例如,假设有一个复合索引(例如 index_a_b_c),它包含三个字段 a, b, c。如果你执行的查询只使用了 a 字段进行筛选,那么 key_len 可能只包含字段 a 的长度。如果查询使用了 ab 两个字段进行筛选,key_len 会增加,以反映更多的索引字段被使用。

  • 因此,当 key_len 较长时,意味着查询充分利用了索引的多个部分,这通常可以提高查询效率。

第二句:key_len 越小,索引效果越好

解释

  • 这句话强调了索引的选择性和效率。key_len 越小,表示查询使用的索引部分越少,也可能意味着查询的目标更加精准,过滤的行数越少。

  • 如果一个查询只需使用索引的前几列(即 key_len 较小),并且可以快速过滤掉大部分不相关的行,那么该查询的效率通常会更高。

  • 在某些情况下,使用较小的 key_len 可能会比使用较大的 key_len 更有效,因为这减少了不必要的索引扫描(特别是当大部分行都匹配前面的字段时)。

如何综合理解这两句话

这两句话并不矛盾,而是从不同的角度解释了 key_len 的作用:

  1. 充分利用索引:当你希望尽可能利用复合索引的多个字段时,较大的 key_len 是有利的,因为它表明查询条件使用了索引的多个部分,从而可能减少全表扫描的需求。

  2. 索引的效率:另一方面,较小的 key_len 可能意味着查询条件已经足够过滤掉大多数不匹配的行,从而更快地找到所需的记录。

实际应用中的考量

  • 复合索引:如果你的查询经常使用复合索引的前几个字段,而不使用全部字段,那么你可能希望 key_len 较小,这样查询效率可能更高,因为数据库引擎不需要扫描索引的所有部分。
  • 单字段索引:如果你有一个单字段索引,那么 key_len 的大小主要取决于这个字段的类型。对于简单的查询,key_len 较小可能是好事。

总结来说,key_len 并不是越大或越小越好,而是要根据查询的具体情况来衡量。当 key_len 充分利用了索引的关键字段,并且有效过滤数据时,这通常是一个高效的查询设计。

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');
  • 使用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 。

    EXPLAIN select * FROM user WHERE id = 1;
    

image-20240817101527149

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

image-20240817101648034

联合索引key_len计算

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

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

image-20240817101849893

1、部分索引生效的情况

我们使用name进行查询

EXPLAIN select * FROM user WHERE name = 'tom';

image-20240817101935511

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

2、联合索引完全使用索引的情况

EXPLAIN select * FROM user WHERE name = '张三' AND age = 19;

image-20240817102038720

由于联合索引,使用到(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
EXPLAIN SELECT * FROM L1 WHERE L1.id='1';

image-20240817102310156

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

image-20240817102402990

什么是驱动表 ?

  • 多表关联查询时,第一个被处理的表就是驱动表,使用驱动表去关联其他表.
  • 驱动表的确定非常的关键,会直接影响多表关联的顺序,也决定后续关联查询的性能

驱动表的选择要遵循一个规则:

在对最终的结果集没有影响的前提下,优先选择结果集最小的那张表作为驱动表

3.8、rows 字段

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

  1. 使用like 查询,会产生全表扫描, L2中有3条记录,就需要读取3条记录进行查找
EXPLAIN SELECT * FROM L1,L2 WHERE L1.id = L2.id AND L2.title LIKE '%tes%';

image-20240817102659704

  1. 如果使用等值查询, 则可以直接找到要查询的记录,返回即可,所以只需要读取一条
EXPLAIN SELECT * FROM L1,L2 WHERE L1.id = L2.id AND L2.title = 'test03';

image-20240817102753104

总结: 当我们需要优化一个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在查询过程中的一些详细信息

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);
  • Using filesort
EXPLAIN SELECT * FROM users ORDER BY age;

执行结果Extra为Using filesort ,这说明,得到所需结果集,需要对所有记录进行文件排序。这类SQL语句性能极差,需要进行优化。

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

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

image-20240817103436525

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

image-20240817103538258

执行结果Extra为Using temporary ,这说明需要建立临时表 (temporary table) 来暂存中间结果。性能消耗大, 需要创建一张临时表, 常见于group by语句中. 需配合SQL执行过程来解释, 如果group by和where索引条件不同, 那么group by中的字段需要创建临时表分组后再回到原查询表中.如果查询条件where和group by是相同索引字段, 那么就不需要临时表.

  • Using where
EXPLAIN SELECT * FROM users WHERE age=10;

image-20240817103640773

此语句的执行结果Extra为Using where,表示使用了where条件过滤数据。需要注意的是:

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

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

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

image-20240817103834388

此句执行结果为Extra为Using index,说明sql所需要返回的所有列数据均在一棵索引树上,而无需访问实际的行记录。

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

需要进行嵌套循环计算.

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

image-20240817105001232

没有显示 Using join buffer,可能是因为查询优化器在这个具体的场景下能够有效地使用索引,因此不需要使用连接缓冲区。在这种情况下,MySQL 直接使用了 ref 类型的连接(通过索引进行连接),而不是需要缓冲区的嵌套循环连接。

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

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

image-20240817105131768

执行结果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服务器必须访问存储引擎的次数。

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');

接着,我们在 last_nameage 字段上创建复合索引:

CREATE INDEX idx_lastname_age ON employees(last_name, age);

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

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

image-20240817110406345

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

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

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

总结:

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

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

https://mp.weixin.qq.com/s?__biz=MzkwOTczNzUxMQ==&mid=2247484180&idx=1&sn=2cfeba47a57b0d27d297de2037928080&chksm=c137685cf640e14abf7215d3a063e199b1d9aabf5e659b5113230bfea3a5a79ec84479545682#rd

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2052367.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

爆火的本地知识库项目是什么?什么是RAG?本地知识库与大模型的关系

“ 本地知识库就相当于大模型的外部资料库。” 很多人应该都听过本地知识库项目&#xff0c;它是当今人工智能领域爆火的项目之一&#xff0c;那么到底什么是本地知识库&#xff1f;它和大模型有什么关系&#xff1f;怎么构建本地知识库&#xff1f; 01 — 为什么需要本地知…

Docker的介绍、保姆级安装和使用

一、Docker简介 1.1、Docker是什么 Docker是一个用于开发、发布和运行应用程序的开放平台;使您能够将应用程序与基础设施分离,以便您可以快速交付软件。不像虚拟机那样笨重(比如:我需要将一个安装好nginx环境的内容分享给其他人: 方式一【使用虚拟】(应用程序Nginx与基…

系统架构设计师 - 软件工程(2)

软件工程 软件工程&#xff08;13-22分&#xff09;非常重要软件系统建模系统设计界面设计 ★★软件设计结构化设计 ★★面向对象设计 ★★★★★基本过程设计原则设计模式创建型模式&#xff1a;创建对象结构型模式&#xff1a;更大的结构行为型模式&#xff1a;交互及职责分配…

四川财谷通信息技术有限公司抖音小店优势解析

在数字经济蓬勃发展的今天&#xff0c;电商平台如雨后春笋般涌现&#xff0c;其中&#xff0c;四川财谷通信息技术有限公司旗下的抖音小店凭借其独特的优势和强大的实力&#xff0c;在众多竞争者中脱颖而出&#xff0c;成为消费者和商家信赖的优选平台。本文将详细解析四川财谷…

Windows键快捷键大全

Windows键快捷键大全 Windows键结合其他键可以执行多种快捷操作&#xff0c;以下是一些常用的Windows键快捷键&#xff1a; Windows键 D: 显示或隐藏桌面。Windows键 E: 打开文件资源管理器。Windows键 L: 锁定电脑。Windows键 R: 打开运行对话框。Windows键 I: 打开Win…

Java中JDK动态代理

参考&#xff1a;疯狂Java讲义 第18章 文章目录 前言复杂度与耦合的矛盾 使用JDK动态代理总结 前言 复杂度与耦合的矛盾 开发实际应用的软件系统时&#xff0c;通常会存在相同代码段重复出现的情况&#xff0c;在这种情况下&#xff0c;一般都提取为一个方法&#xff0c;在不…

SOP企业内部推行:效率飙升100%,质量保障零瑕疵!

在企业的日常运营中&#xff0c;你是否经常遇到这样的问题&#xff1a;同样一项工作&#xff0c;不同的人做出来效果却大相径庭&#xff1f;或者&#xff0c;明明已经制定了工作流程&#xff0c;但执行起来却总是出现偏差&#xff0c;导致效率低下、质量不稳&#xff1f;这些问…

【STM32单片机_(HAL库)】3-2-2【中断EXTI】【电动车报警器项目】继电器定时开闭

1.硬件 STM32单片机最小系统继电器模块 2.软件 继电器模块alarm驱动文件添加GPIO常用函数main.c程序 #include "sys.h" #include "delay.h" #include "led.h" #include "alarm.h"int main(void) {HAL_Init(); …

海外服务器和内地服务器有什么区别?

海外服务器和内地服务器在许多方面存在区别&#xff0c;主要包括以下几个方面&#xff1a; 1. 地理位置 海外服务器&#xff1a;位于中国大陆以外的地区&#xff0c;比如美国、欧洲、东南亚等地。常见的海外服务器提供商有Amazon Web Services&#xff08;AWS&#xff09;、Goo…

稚晖君发布5款全能人形机器人,开源创新,全能应用

8月18日&#xff0c;智元机器人举行“智元远征 商用启航” 2024年度新品发布会&#xff0c;智元联合创始人彭志辉主持并发布了“远征”与“灵犀”两大系列共五款商用人形机器人新品——远征A2、远征A2-W、远征A2-Max、灵犀X1及灵犀X1-W&#xff0c;并展示了在机器人动力、感知、…

【LLM之Base Model】Weaver论文阅读笔记

研究背景 当前的大型语言模型&#xff08;LLM&#xff09;如GPT-4等&#xff0c;尽管在普通文本生成中表现出色&#xff0c;但在创造性写作如小说、社交媒体内容等方面&#xff0c;往往不能很好地模仿人类的写作风格。这些模型在训练和对齐阶段&#xff0c;往往使用的是大规模…

Java | Leetcode Java题解之第347题前K个高频元素

题目&#xff1a; 题解&#xff1a; class Solution {public int[] topKFrequent(int[] nums, int k) {Map<Integer, Integer> occurrences new HashMap<Integer, Integer>();for (int num : nums) {occurrences.put(num, occurrences.getOrDefault(num, 0) 1);…

【layui】layer弹出图片层(开启图片旋转 放大 缩小 还原)

详细参照layui官网组件 弹出层组件 &#x1f525;Photots —————————————————————————— 弹出图片层&#xff08;开启图片旋转 放大 缩小 还原&#xff09;是layui2.8.16的新增功能&#xff0c; 新增 photos 层的鼠标滚轮缩放功能 是layui2.8.16的新增…

8.17模拟赛题解

先考虑空间能不能把N个座位放好 最优的方式就是挨着摆放 那么一排能摆放QL/x的商个椅子 &#xff0c;然后计算摆放完N个座位需要多少排&#xff0c;N/Q 向上取整 计算所需要的排总共占据多宽&#xff0c;讨论有没有超过W&#xff0c;然后讨论剩余空间还能放几条走廊 如果走廊数…

蚓链数字化营销:连接心灵的新桥梁

在当今数字化浪潮汹涌的时代&#xff0c;营销领域也经历了一场深刻的变革。蚓链数字化营销&#xff0c;已不仅仅是一种推广手段&#xff0c;更是连接品牌与消费者心灵的新桥梁&#xff0c;让每一次互动都充满温度与价值。 曾经&#xff0c;品牌与消费者之间的沟通隔着一层厚厚…

小白零基础学数学建模系列-Day8-多目标规划问题与案例实践

文章目录 1. 引言1.1 优化问题的背景1.2 单目标规划与多目标规划的概述 2. 单目标规划2.1 定义2.2 应用场景2.3 求解方法2.4 案例&#xff1a;制造企业生产成本最小化的优化方案2.4.1 案例背景2.4.2 模型建立2.4.3 模型求解2.4.4 结果分析2.4.5 总结 3. 多目标规划3.1 定义3.2 …

【MySQL进阶之路】数据库的操作

目录 创建数据库 字符集和校验规则 查看数据库支持的字符集 查看数据库支持的字符集校验规则 指定字符集和校验规则 在配置文件中配置 查看数据库 显示创建语句 修改数据库 删除数据库 数据库的备份和恢复 备份整个数据库 备份特定表 备份多个数据库 备份所有数据…

无人机测绘技术及应前景详解

无人机测绘技术是一种将无人机技术、遥感技术、地理信息系统&#xff08;GIS&#xff09;和计算机技术相结合&#xff0c;对自然地理要素或地表人工设施的形状、大小、空间位置及其属性等进行测定、采集并绘制成图的技术。它利用高精度传感器&#xff08;如激光雷达、航拍相机等…

遗传进化算法进行高效特征选择

在构建机器学习模型时&#xff0c;特征选择是一个关键的预处理步骤。使用全部特征往往会导致过拟合、增加计算复杂度等问题。因此&#xff0c;我们需要从原始特征集中选择一个最优子集&#xff0c;以提高模型的泛化性能和效率。 特征选择的目标是找到一个二元掩码向量&#xf…

液相色谱仪仪器校准怎么做?具体校准方法是什么?

液相色谱法概述 液相色谱仪是由输液系统、进样系统、分离系统、检测系统和数据处理系统等部分组成的分析仪器。液相色谱仪是根据样品之中各组分在色谱柱中的固定相和流动相间的分布或吸附特性的差异&#xff0c;流动相将样品带入色谱柱进行分离。由检测器检测&#xff0c;并由…