谈到索引失效,大家可能都能列举出几个场景,比如:后模糊查询、条件中带函数、索引中断等等 。今天我想和你分享另一个场景:索引成本分析 。
我先用一个具体的例子来描述一下这个场景 。
案例场景假设现在我们有一张人物表,建表语句如下:
create TABLE `person` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `score` int(11) NOT NULL, `create_time` timestamp NOT NULL, PRIMARY KEY (`id`),) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
并创建两个索引:
KEY `name_score` (`name`,`score`) USING BTREE,KEY `create_time` (`create_time`) USING BTREE
然后插入 10 万条数据:
create DEFINER=`root`@`%` PROCEDURE `insert_person`()begin declare c_id integer default 1; while c_id<=100000 do insert into person values(c_id, concat('name',c_id), c_id+100, date_sub(NOW(), interval c_id second)); -- 需要注意,因为使用的是now(),所以对于后续的例子,使用文中的SQL你需要自己调整条件,否则可能看不到文中的效果 set c_id=c_id+1; end while;end
数据插入后,我们用下面的 SQL 进行查询:
explain select * from person where NAME>'name84059' and create_time>'2020-01-24 05:00:00'
文章插图
通过上面的执行计划可以看到:type=All,说明是全表扫描 。
接着我们把 create_time 条件中的 5 点改为 6 点:
explain select * from person where NAME>'name84059' and create_time>'2020-01-24 06:00:00'
文章插图
执行计划显示:type=range,key=create_time,走了 create_time 索引,而不是 name_score 联合索引 。
看到这里,你是不是很诧异?接下来,我们就一起来分析一下这背后的原因 。
原因分析MySQL 在查询数据之前,会先对可能的方案做执行计划,然后依据成本决定走哪个执行计划 。这里的成本,包括 IO 成本和 CPU 成本:
- • IO 成本,是从磁盘把数据加载到内存的成本 。默认情况下,读取数据页的 IO 成本常数是 1(也就是读取 1 个页成本是 1) 。
- • CPU 成本,是检测数据是否满足条件和排序等 CPU 操作的成本 。默认情况下,检测记录的成本是 0.2 。
SHOW TABLE STATUS LIKE 'person'
文章插图
从图中可以看到,总行数是 100086 行,由于 MySQL 的统计信息是一个估算,这里多了 86 行是正常的 。CPU 成本是 100086*0.2=20017 左右 。
数据长度是 4734976 字节 。对于 InnoDB 来说,4734976 就是聚簇索引占用的空间,等于聚簇索引的页数量 * 每个页面的大小 。InnoDB 每个页面的大小是 16KB,大概计算出页的数量是 289,因此 IO 成本是 289 左右 。
所以,全表扫描的总成本是 20306 左右 。
在 MySQL 5.6 及之后的版本中,我们可以使用 optimizer trace 功能查看优化器生成执行计划的整个过程 。
SET optimizer_trace="enabled=on";explain select * from person where NAME >'name84059' and create_time>'2020-01-24 05:00:00';select * from information_schema.OPTIMIZER_TRACE;SET optimizer_trace="enabled=off";
对于按照 create_time>'2020-01-24 05:00:00’ 条件走全表扫描的 SQL,我从 OPTIMIZER_TRACE 的执行结果中,摘出了几个重要片段来重点分析:1、使用 name_score 对 name84059<name 条件进行索引扫描需要扫描 25362 行,成本是 30435 。
{ "index": "name_score", "ranges": [ "name84059 < name" ], "rows": 25362, "cost": 30435, "chosen": false, "cause": "cost"}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 肺癌晚期到底还要不要治? 肺癌晚期能治吗
- 要不要为爱情奋不顾身,为爱情奋不顾身值得吗-
- 领导加微信怎么打招呼望多指教 方便联系工作,领导加你微信后要不要打招呼-
- 化妆|夏季化妆有什么技巧?想要不脱妆最好这样做,妆容持久还服帖
- 酸豆角要不要炒,酸豆角不炒可以直接吃吗-
- 炒面面煮好后要不要过凉水,炒面煮熟后要过冷水吗-
- 香辣虾炸虾的时候要不要淀粉,虾可以裹淀粉炸吗--
- 幽门螺杆菌检讨阳性毕竟要不要治? 幽门螺旋杆菌阳性是什么意思?
- 车辆的商业险到底要不要买? 汽车商业险可以不买吗
- 等额本息30年的房贷要不要提前还款,到底划不划算?