1.  现象

表结构如下

CREATE TABLE `ACT_HI_INST` (
`ID` varchar(64) COLLATE utf8_bin NOT NULL COMMENT '主键',
`INST_ID_` varchar(64) COLLATE utf8_bin NOT NULL COMMENT '流程实例id',
`BUSINESS_KEY_` varchar(255) COLLATE utf8_bin DEFAULT '' COMMENT '流程编号',
`CREATE_TIME_` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UPDATE_TIME_` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`ID`),
UNIQUE KEY `UIDX_INST` (`INST_ID_`),
UNIQUE KEY `UIDX_BKEY` (`BUSINESS_KEY_`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin
执行下面语句, 发现没有走索引
explain
SELECT
*
FROM ACT_HI_INST hi
ORDER BY hi.BUSINESS_KEY_ DESC;

select count(*) from ACT_HI_INST ;
--

同时我们发现rows与实际表的数量存在差异,使用下面语句重新统计索引信息, 更正统计信息, 更新之后发现 rows 就数据表的数量基本一致(不完全一样是因为rows是采样统计而来的)。

analyze table ACT_HI_INST;

也就是说对于下面这条语句,尽管BUSINESS_KEY_  上有索引,MySQL还是选择了全表扫描。为什么会这样呢?

SELECT * FROM ACT_HI_INST hi ORDER BY hi.BUSINESS_KEY_ DESC;

2. 猜想

我猜想原因是 因为MySQL认为即使 使用 BUSINESS_KEY_  索引树进行查询,不需要排序,但是最后仍然需要回表,回表的次数 == 表的大小,这种代价比全表扫描然后排序的代价更大。

3. 验证

为了验证我的猜想,我加上在SQL语句最后加上 LIMIT 10 。如下所示

explain
SELECT
*
FROM ACT_HI_INST hi
ORDER BY hi.BUSINESS_KEY_ DESC limit 10;

果然我们看到加上 LIMIT 的语句走了索引。因为这个时候MySQL认为回表的代价比排序的代价更小,所以这个时候选择了走 BUSINESS_KEY_  索引。

除了上面这种方式可以验证我的猜想,还有一种方式,如下所示。我们只查询BUSINESS_KEY_ 。

因为此时叶子节点就包含我们需要查询的字段,这个时候不需要再回表,所以MySQL选择BUSINESS_KEY_  代价最小。

explain
SELECT
hi.BUSINESS_KEY_
FROM ACT_HI_INST hi
ORDER BY hi.BUSINESS_KEY_ DESC ;

4. 补充

这部分主要来源于极客时间林晓斌老师的《MySQL实战45讲》第16讲

order by a

如果 a 字段上有索引,MySQL innodb引擎是按照上诉的方式进行选择。如果a字段上没有索引,MySQL  innodb引擎 就会有两种排序方式:

全字段排序 和 rowid 排序。

全字段排序:将所有要选择的字段加入到sort_buffer中,然后在内存或者外部进行排序。如果能在内存中进行排序就在内存中进行排序。

如果要排序的数据量小于 sort_buffer_size,排序就在内存中完成。但如果排序数据量太大,内存放不下,则不得不利用磁盘临时文件辅助排序。

如果查询要返回的字段很多的话,那么 sort_buffer 里面要放的字段数太多,这样内存里能够同时放下的行数很少,要分成很多个临时文件,排序的性能会很差。这个时候MySQL就会采用rowId排序。

rowid排序:MySQL取出需要排序的字段和ID放入sort_buffer中进行排序,最后按照排序的结果,通过ID回表,返回数据到客户端。

MySQL 的一个设计思想是如果内存够,就要多利用内存,尽量减少磁盘访问。所以对应sort_buffer足够大的情况,MySQL会优选选择全字段排序。

【开发总结】order by 为什么没有走索引?的更多相关文章

  1. sql查询未走索引问题分析之查询数据量过大

    前因: 客户咨询,有一个业务sql(代表经常被执行且重要),全表扫描在系统占用资源很高(通过ash报告查询得到信息) 思路: 1.找到sql_text,sql_id 2.查看执行计划 3.查询sql涉 ...

  2. mysql 索引 create_time 加explain关键字是否走索引

    SELECT * FROM t_user WHERE email='217@xxg.com';  --1.725 --加email索引之后 0.003 SELECT * FROM t_user WHE ...

  3. Oracle中查询走索引的情况

    1.对返回的行无任何限定条件,即没有where子句 2.未对数据表与任何索引主列相对应的行限定条件例如:在City-State-Zip列创建了三列复合索引,那么仅对State列限定条件不能使用这个索引 ...

  4. varchar int 查询 到底什么情况下走索引?

    一个字符类型的.一个int类型的,查询的时候到底会不会走索引,其实很多工作了几年的开发人员有时也会晕,下面就用具体事例来测试一下. 1.  准备工作 先准备2张表,以备后续测试使用. 表1:创建表te ...

  5. 如何根据执行计划,判断Mysql语句是否走索引

    如何根据执行计划,判断Mysql语句是否走索引

  6. 以通配符(%)开始的like字符串,走索引

    在对oracle的SQL优化过程中经常会遇到[like'%abc']破坏索引的问题,但是如果真有此类需求,该如何在不破坏索引的基础上进行查询呢. [sql] view plain copy sys@m ...

  7. mysql中关于关联索引的问题——对a,b,c三个字段建立联合索引,那么查询时使用其中的2个作为查询条件,是否还会走索引?

    情况描述:在MySQL的user表中,对a,b,c三个字段建立联合索引,那么查询时使用其中的2个作为查询条件,是否还会走索引? 根据查询字段的位置不同来决定,如查询a,     a,b    a,b, ...

  8. MySQL实现强制查询走索引和强制查询不缓存

    0.表结构如下:(包含两个索引) Create Table: CREATE TABLE `user` ( `userID` ) NOT NULL, `userCode` ) DEFAULT NULL, ...

  9. 强制MySQL查询走索引和强制查询不缓存

    有些情况下,表中创建了索引但是EXPLAIN的查看执行计划的时候发现并没有走索引.是因为优化器认为该语句不使用索引效率更好. 当然也可以强制走索引.类似: SELECT uid,uname FROM ...

随机推荐

  1. 用心整理的 献丑啦 一些关于http url qs fs ...模块的方法

    http:  const http = require("http");  http.createServer((req , res)=>{  req:request 请求  ...

  2. keil5 使用JLink 向nrf52840DK 下载程序出现No Cortex-M SW Device Found

    今天打开52840 keil5 工程,下载程序无法下载成功,提示如下: 在Jlink 配置中(Option for target....-> Debug->Setting )SWDIO也无 ...

  3. 11.oracle 事务

    一.什么是事务事务用于保证数据的一致性,它由一组相关的dml语句组成,该组的dml(数据操作语言,增删改,没有查询)语句要么全部成功,要么全部失败.如:网上转账就是典型的要用事务来处理,用于保证数据的 ...

  4. ThinkCMF&Thinkphp 首页静态化处理

    基于TP5的页面静态化教程 1.首页在控制器添加以下代码生成静态页面文件 $info = $this->buildHtml("/staticIndex", 'static', ...

  5. ElasticSearch-生命周期管理

    1月29日,Elastic Stack 迎来 6.6 版本的发布,该版本带来很多新功能,比如: Index Lifecycle Management Frozen Index Geoshape bas ...

  6. Prometheus监控神器-Alertmanager篇(4)

    本章节主要讲解Alertmanager高可用的搭建与配置的详细的知识内容. 为了提升Prometheus的服务可靠性,我们会部署两个或多个的Prometheus服务,两个Prometheus具有相同的 ...

  7. Java方法传参,测试在方法内部改变参数内容是否会影响到原值

    我分了三种类型的参数进行测试 一.基本类型 public static void main(String[] args) { System.out.println("验证基本类型int作为参 ...

  8. 硬核干货:4W字从源码上分析JUC线程池ThreadPoolExecutor的实现原理

    前提 很早之前就打算看一次JUC线程池ThreadPoolExecutor的源码实现,由于近段时间比较忙,一直没有时间整理出源码分析的文章.之前在分析扩展线程池实现可回调的Future时候曾经提到并发 ...

  9. 夜息seo培训内部教程

    http://www.wocaoseo.com/thread-268-1-1.html 随着SEO日益正规化,在企业中推行SEO变得越来越重要,在上一文<将SEO整合入整个网站项目>中也有 ...

  10. 【原创】探索云计算容器底层之Cgroup

    一.什么是Cgroup,使用场景? 容器本质上是进程,既然是进程就会消耗掉系统资源,比如:CPU.内存.磁盘.网络带宽等,如果不加以限制,容器在某些情况下就会无限制地吃掉宿主机的系统资源,显然这不是我 ...