看别人的代码为什么会有 force index这样的语句

573 阅读3分钟

「这是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战

在查看别人的代码或者自己写代码的时候偶尔会看到在查询的SQL语句中有force index 这样的语句,例如下面的查询SQL:

SELECT * FROM t_user force index(idx_birthday) WHERE  birthday <'2021-11-20'  and birthday >='2021-11-19'

在查询的时候强制让查询的语句让查询的时候采用idx_birthday索引,那么为什么我们会去干涉数据库使用索引呢?

在查询语句真正开始执行的时候,优化器会根据索引扫描的行数选择索引,优化器选择索引是为了找到一个最优的查询方案,能够查询的时候采用最小的时间代价及性能代价去执行我们需要查询的语句,优化器在选择索引的时候最关键的指标就是:扫描的数据库行数,扫描的行数越少,这样的话读取的磁盘次数就会越少,消耗的资源也会越少。在优化器选择索引的时候也会考虑在查询的过程中,会考虑排序、采用临时表等因素来综合考虑判断。在查询的语句中加入force index 这样强制索引目的就是优化器选择的出来的索引不是我们认为的最优索引,就强制让优化器采用我们自己的认为的索引。

成本计算

数据库在选择索引的时候,会考虑查询的成本代价,查询成本=I/O成本+CPU成本,I/O成本指的是将数据从磁盘读取到内存中的成本,CPU成本指的是数据读取到内存后,需要判断数据是否满足条件,以及对查询的结果集进行排序等操作都需要耗费CPU的性能,就称为CPU成本,这两种成本,在InnoDB里面都设了一个默认的成本因子:读取数据页的成本因子是:1.0,判断条件的成本因子是:0.2。例如下面的查询语句,成本计算可以这样计算,假设数据行数有1000行,data_length的长度为:185623

  • 全表扫描的成本

查询成本=185623/16/1024 * 1.0+1000 * 0.2≈11.4+200 ≈211.4,那么全表扫描的查询成本就是:211.4,185623/16/1024:是计算数据的长度大概占了多少页,数据库读取磁盘数据到内存按照页的维度来读取的。

  • idx_birthday的成本:假如满足条件的数据行数有100个满足条件,假如只涉及一个数据页

查询成本=索引查找成本+回表查询成本=(1 * 1.0+100 * 0.2)+(100 * 1.0+100 * 0.2)=21+120=144

从上面的两种计算中,可以看出走索引的成本比全表扫描的成本少,所以就会走索引查找,但是如果我们将满足索引的数据量个数加大为500,那么计算出来的代价就是:541,这个数据就会明显高于全表扫描的成本,这样的话索引优化器就会走全表扫描,但是这成本计算只是个预估值,并不是准确的数据,实际上走索引的速度会高于全表扫描的成本,这个时候为了强制走idx_birthday索引,不让查询的时候去全表扫描。