MySQL范围查找时,索引失效问题探究

Java之间

共 2363字,需浏览 5分钟

 ·

2021-11-28 14:45

往期热门文章:

1、有了 for (;;) ,为什么还需要while (true) ?到底哪个更快?

2、名企公开挂“加班真好”标语,员工称一年被免费“白嫖”600多小时!网友看不下去了,稽查部门展开调查...

3、面试官:为什么 Java 不把基本类型放在堆中?我竟然答不上来。。

4、IDEA 注释模板这样搞!

5、后端开挂:3行代码写出8个接口!

来源:blog.csdn.net/qq_25188255/

article/details/81316498

1 问题描述

本文对建立好的复合索引进行排序,并取记录中非索引字段,发现索引不生效,例如,有如下表,DDL语句为:
CREATE TABLE `employees` (
  `emp_no` int(11NOT NULL,
  `birth_date` date NOT NULL,
  `first_name` varchar(14NOT NULL,
  `last_name` varchar(16NOT NULL,
  `gender` enum('M','F'NOT NULL,
  `hire_date` date NOT NULL,
  `age` int(11NOT NULL,
  PRIMARY KEY (`emp_no`),
  KEY `unique_birth_name` (`first_name`,`last_name`USING BTREE
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
复合索引为unique_birth_name (first_name,last_name) 。使用以下语句:
EXPLAIN SELECT
    gender
FROM
    employees
ORDER BY
    first_name,
    last_name
根据上图:type:all 及 Extra:Using filesort 可得,索引没有生效。
继续进行试验,对查询语句进一步改写,加上一个范围查找:
EXPLAIN SELECT
    gender
FROM
    employees
WHERE first_name > 'Leah'
ORDER BY
    first_name,
    last_name
执行计划显示如下图:
这里发现结果和第一次sql分析无异。继续试验。
改写sql语句:
EXPLAIN SELECT
    gender
FROM
    employees
WHERE first_name > 'Tzvetan'
ORDER BY
    first_name,
    last_name
此时,令人惊讶的是,索引生效了。

2 问题分析

此时,我们做一个大胆的猜测:
第一次进行sql分析时,因为第一次order by 后,得到的还是全表数据,如果根据复合索引中携带的主键查找每一个gender进行拼接,自然很费资源和时间,mysql不会做如此蠢的事。不如直接进行全表扫描,把扫描到的每条数据和order by得到的临时数据进行拼接,从而得到需要的数据。
为了验证上述想法的正确性,我们对三次sql进行分析。
第一次sql根据复合索引得到的数据量为:300024,为全表数据
SELECT
    COUNT(first_name)
FROM
    employees
ORDER BY
    first_name,
    last_name
第二次改写的sql根据复合索引得到的数据量为:159149 , 为全表数据量的1/2。
SELECT
    COUNT(first_name)
FROM
    employees
WHERE first_name > 'Leah'
ORDER BY
    first_name,
    last_name
第三次改写的sql根据复合索引得到的数据量为:36731, 为全表数据量的1/10。
SELECT
    COUNT(first_name)
FROM
    employees
WHERE first_name > 'Tzvetan'
ORDER BY
    first_name,
    last_name
通过对比发现,第二次改写的sql根据复合索引得到的数据量是全表数据量的1/2。此时还没有达到mysql使用索引进行二次查找的量级。
第三次改写的sql根据复合索引得到的数据量是全表数据量的1/10,达到了mysql使用索引进行二次查找的量级,于是从执行计划上可以看到,第三次改写sql是走了索引的。

3 总结

mysql 是否根据首次索引条件查询出的主键进行二次查找,也是要看查询出来的数据量级,如果数据量接近全表数据量的话,就会进行全表扫描,否则根据第一次查询出来的主键进行二次查询。

最近热文阅读:

1、有了 for (;;) ,为什么还需要while (true) ?到底哪个更快?
2、名企公开挂“加班真好”标语,员工称一年被免费“白嫖”600多小时!网友看不下去了,稽查部门展开调查...
3、面试官:为什么 Java 不把基本类型放在堆中?我竟然答不上来。。
4、IDEA 注释模板这样搞!
5、后端开挂:3行代码写出8个接口!
6、推荐一款可视化配置 Nginx 的神器
7、一款性能调优利器 — 火焰图
8、Redis 实现限流的三种方式
9、推荐 15 款常用开发工具
10、一次 QPS 翻倍的 Java 服务性能优化
关注公众号,你想要的Java都在这里

浏览 38
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报