0
点赞
收藏
分享

微信扫一扫

mysql索引在什么场景会失效(8.0版本)

上古神龙 2022-04-05 阅读 21
mysql

这里测试普通索引和组合索引在哪些场景中失效(一张表只能使用一个索引)

1、创建user表,其中idx_code_age_name为组合索引,由code、age、name字段组成。idx_height为普通索引。

CREATE TABLE `user` (
	`id` INT NOT NULL AUTO_INCREMENT,
	`code` VARCHAR ( 20 ) COLLATE utf8mb4_bin DEFAULT NULL,
	`age` INT DEFAULT '0',
	`name` VARCHAR ( 30 ) COLLATE utf8mb4_bin DEFAULT NULL,
	`height` INT DEFAULT '0',
	`address` VARCHAR ( 30 ) COLLATE utf8mb4_bin DEFAULT NULL,
	PRIMARY KEY ( `id` ),
	KEY `idx_code_age_name` ( `code`, `age`, `name` ),
KEY `idx_height` ( `height` ) 
) ENGINE = INNODB AUTO_INCREMENT = 4 DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_bin;

2、初始化表里面的数据

INSERT INTO user (id, code, age, name, height, address) VALUES (1, '101', 21, '周星驰', 175,'香港');
INSERT INTO user (id, code, age, name, height, address) VALUES (2, '102', 18, '周杰伦', 173,'台湾');
INSERT INTO user (id, code, age, name, height, address) VALUES (3, '103', 23, '苏三', 174,'成都');
INSERT INTO user (id, code, age, name, height, address) VALUES (4, '104', 23, '周润发', 174,'香港');
INSERT INTO user (id, code, age, name, height, address) VALUES (5, '104', 23, '周星星', 174,'香港');

3、开始测试索引使用

  • 正常使用索引的例子(注意条件建议按照精准过滤的放左边,组合索引按照最左缀原则,虽然mysql会根据条件的顺序进行优化,比如组合索引是 code、name,先使用code在name也是可以的

    # 这里使用了主键索引查询
    EXPLAIN select * from user where id = 1;
    
    # 根据组合索引最左缀的字段查询code
    EXPLAIN select * from user where code = '101';
    
    # 根据组合索引最左缀的字段查询code、age
    EXPLAIN select * from user where code = '174' and age = 21;
    
    # 根据组合索引最左缀的字段查询code、age、name
    EXPLAIN select * from user where code = '174' and age = 21 and name = '周星驰';
    
    # 根据普通索引height,组合索引code、age、name,测试结果发现这里优先使用了组合索引,height字段没有走索引
    EXPLAIN select * from user where height = 174 and code = '101' and age = 21 and name = '周星驰';
    
    # 根据普通索引height
    EXPLAIN select * from user where height = 174;
    
    # 只查询索引的字段, 注意这里返回的字段需要在同一颗b+树上面否则会失效
    EXPLAIN select code, age, name from user;
    
    # 使用or关键字,发现最终走了两个所以是怎么一回事呢?应该是底层优化,使用了union拆分成两张表索引走了两个索引
    EXPLAIN select * from user where code = '101' or height = 172;
    

    下面是测试的执行计划
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/fc70b8501f824860b928af7b84774c4e.png
    在这里插入图片描述

  • 索引失效的例子

    # 根据组合索引的code字段查询,code字段的类型是varchar, 而给的值是int类型
    # mysql会在优化sql时隐式转换导致索引失效
    EXPLAIN select * from user where code = 101;
    
    # 根据组合索引的code、name字段查询,name字段不符合最左匹配原则,name依赖age字段排序,所以这里只有code使用到了索引
    EXPLAIN select * from user where code = '101' and name = '周星驰';
    
    # 根据组合索引的code、name、age字段查询,这里的code隐式转换已经失效,自然依赖于code字段的索引全部失效
    EXPLAIN select * from user where code = 101 and age = 21 and name = '周星驰';
    
    # 根据组合索引的code、name、age字段查询, code字段 > < != 都只会走这个索引,后面依赖code字段索引会失效
    EXPLAIN select * from user where code > '101' and age = 21 and name = '周星驰';
    EXPLAIN select * from user where code < '101' and age = 21 and name = '周星驰';
    EXPLAIN select * from user where code not in ('101') and age = 21 and name = '周星驰';
    
    #根据组合索引的code、name、age字段,普通索引height查询,为什么这里又走了索引?mysql优化后判断,组合索引只走了一个对比普通索引,普通索引效率更高就使用了普通索引字段。
    EXPLAIN select * from user where code > '101' and age = 21 and name = '周星驰' and height = 174;
    
    # 使用select * 查询
    EXPLAIN select * from user;
    # 使用覆盖索引,name、code、age是组合索引,该b+树的叶子节点的值为主键索引ID的值,但是height是在另外一课b+树上,所以这里索引失效了
    EXPLAIN select id,name, code, age, height from user;
    

    测试结果
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 索引失效的例子

    # 根据主键ID查询,对查询的字段进行计算导致索引失效
    EXPLAIN select * from user where id + 1 = 4;
    
    # 根据组合索引code查询,在索引字段使用函数导致索引失效
    EXPLAIN select * from user where concat(code, "4") =  '1044';
    
    # 根据组合索引code查询 使用like关键字,最终所以失效,也好理解,在b+树中varcha类型是根据ascii编码表进行的排序,最左边的字母都不确定是哪一个肯定就不知道怎么取匹配这个数据,所以走的全表扫描
    EXPLAIN select * from user where code like '%周星星%';
    
    # 使用主键ID匹配普通索引,假设需求是同一张表中两个字段一致的数据查询出来,这里age和height两个字段的类型是一致的,最终只走了code字段的索引
    EXPLAIN select * from user where code = '101' and age = height;
    
    # 使用or关键字,使用索引字段code、height,非索引字段address,我个人理解是这样的,code和height可以走索引合并,但是address没加索引,所以这个字段只能通过全文扫描从而导致索引失效。
    EXPLAIN select * from user where code = '101' or height = 172 or address = '成都';
    
    # 使用not in关键字查询,可能会导致索引失效,有时候索引能走
    EXPLAIN select * from user where code not in ('101','102','103','104');
    
    # 使用not exists , t2走了索引,t1的id是没办法走索引的,但是t1表可以增加正常的索引字段也是没问题的,比如t1.code = '101'
    explain select * from user  t1
    where not exists (select 1 from user t2 where t2.height=173 and t1.id=t2.id)
    

    测试结果
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

举报

相关推荐

0 条评论