MySQL是如何对一个查询语句的多个执行 计划评估他的成本的?
- IO成本 : 从磁盘读数据到内存 , 而且 MySQL里都是一页一页读的,读一页是 1.0
- CPU成本: 拿到数据之后,验证他是否符合 搜索条件了,或者是搞一些排序分组之类的事,这些都是耗费CPU资源的, 读 取和检测一条数据是否符合条件的成本是 0.2
select * from t where x1=xx and x2=xx , 有两个索引,分别是针对x1和x2建立的,
- 先看看这个SQL可以用到哪几个索引,此时发现x1 和x2的索引都能用到,他们俩索引就是possible keys。
计算全表扫描的成本


show table status like “表名” ,可以拿到表的统计信息,在对表进行增删改的时候,MySQL 维护这个表的一些统计信息,在这里可以看到rows 和 data_length ,对innodb来说,rows 是估计值
rows就是表里的记录数,data_length就是表的聚簇索引的字节数大小,此时用data_length除以1024 就是kb为单位的大小,然后再除以16kb(默认一页的大小),就是有多少页, 此时知道数据页的数量 和rows记录数,就可以计算全表扫描的成本了。IO成本就是:数据页数量 1.0 + 微调值,CPU成本就是:行记录数 0.2 + 微调值,他们俩相加,就是 一个总的成本值,比如你有数据页100个,记录数有2万条,此时总成本值大致就是100 + 4000 = 4100,在这个左右。
索引成本的计算方法
主键索引,直接查聚簇索引
普通索引,一般两步走,先从二级索引查询一波数据,在根据这波数据的主键去聚簇索引回表查询。
首先,在二级索引里根据条件查一波数据的IO成本,一般是看 你的查询条件涉及到几个范围,比如说name值在25~100,250~350两个区间,那么就是两个范围,否 则name=xx就仅仅是一个范围区间。 一般一个范围区间就粗暴的认为等同于一个数据页,所以此时可能一般根据二级索引查询的时候,这个 IO成本都会预估的很小,可能就是1 1.0 = 1,或者是n 1.0 = n,基本就是个位数这个级别。
根据一个不是怎么太准确的算法估算一 下,查询条件可能会在二级索引里查出多少条数据, 估算出来之后,比如估算可能会查到100条数据,此时从二级索引里查询数据的CPU成本就是100 * 0.2 + 微调值,总之就是20左右而已。
你拿到100条数据之后,就得回表到聚簇索引里去查询完整数据,此时先估算回表到聚簇索引的IO 成本,这里比较粗暴的直接默认1条数据就得回表到聚簇索引查询一个数据页,所以100条数据就是100 个数据页的IO成本,也就是100 * 1.0 + 微调值,大致是100左右
再针对这100条数据去判断,他们是否符合其他 查询条件了,这里耗费的CPU成本就是100 * 0.2 + 微调值,就是20左右。
把上面的所有成本都加起来,就是1 + 20 + 100 + 20 = 141,这就是使用一个索引进行查询的成本的计 算方法。
上次讲到全表扫描发现成本是4100左右,这次根据索引查找可能就141,所以,很多时候,使用 索引和全表扫描,他的成本差距是非常之大的。所以一般就会针对全表扫描和各个索引的成本,都进行 估算,然后比较一下,选择一个成本最低的执行计划。
如何基于各种规则去执行索引计划的?
MySQL 在执行一些复杂的SQL的时候,如何对查询进行重写来优化具体执行计划的。
