设计mysql的专家们把mysql执行查询的方式称为访问方法或者访问类型,也有人叫做访问级别。同一个查询语句可以使用多种不同的访问方法来执行,虽然最后的查询结果都是一样的,但是不同的执行方式花费的成本可能差距巨大。
下面我们来看一个下mysql都有哪些访问方法,以及他们各自的执行效率
假设我们有demo_table表,id列为主键,key2列为唯一二级索引列,key1为普通索引列
1、const
- 通过主键来定位一条记录
select * from demo_table where id = 2;
- 通过唯一二级索引来定位一条记录
select * from demo_table where key2 = 'zhangsan01';
规定通过主键或者唯一二级索引列与常数的等值比较来定位一条记录的访问方法定义为const。
2、ref
有时我们需要通过某个普通二级索引列与常数进行等值比较,比如:
select * from demo_table where key1 = 'abc';
我们知道对于上面用到的二级索引,对应的扫描区间是[‘abc’,‘abc’],这是一个单点扫描区间,==我们可以定位到第一条’abc’的记录,然后沿着记录所在的单向链表向后扫描,直到某条记录不等于’abc’为止。==由于查询的列表是*,因此需要获取到每一条二级索引记录后都需要拿着id再去聚簇索引中查询完整的用户记录,也就是需要执行回表。
由于二级索引不会限制索引列的唯一性,所以通过二级索引查询的记录可能有多条,此时使用二级索引执行查询的代价就取决于扫描区间中的记录条数。
我们把搜索条件为二级索引列与常数进行等值比较,形成的扫描区间为单点扫描区间,采用二级索引来执行查询的访问方法称为ref
3、ref_or_null
有时,我们不仅想找出某个二级索引列的值等于某个常数的记录,而且还想把该列中值为NULL的记录也找出来,比如:
select * from demo_table where key1 = 'abc' OR key1 is NULL;
当使用二级索引而不是全表扫描的方式执行该查询时,对应的扫描区间就是[NULL,NULL]和[‘abc’,‘abc’],此时这种类型的查询所使用的访问方法就称为ref_or_null。
4、range
有时候,我们的查询方法很复杂,比如下面这个sql
select * from demo_table where key2 in (1438,6328) OR (key2 >= 38 and key2 <= 79);
如果使用key2列的索引idx_key2来执行该查询,那么对应的扫描区间就是[1438,1438],[6328,6328], [38,79]。
我们把使用索引执行查询时,对应的扫描区间为若干个单点扫描区间或者范围扫描区间的访问方法称为range(仅包含一个单点扫描区间的访问方法不能称为range访问方法,扫描区间为(负无穷,正无穷)的访问方法也不能称为range)
5、index
我们来看下面这个查询
select key1 from demo_table; // key1是普通二级索引
上面的sql无法形成合适的扫描区间,因为没有条件,无法使用ref或者range的访问方法,但是我们可以直接遍历所有的二级索引记录,因为我们查询的列只有key1,这是一个二级索引列,所以我们不需要回表,这种方式也称为覆盖索引。
我们把这种扫描全部二级索引记录的访问方法称为index访问方法。
6、all
最直接的查询方式就是全表扫描,对应InnoDB来说就是直接扫描全部的聚簇索引记录。
我们把这种使用全表扫描执行查询的访问方法称为all访问方法。
这些访问方法的执行级别排名
效率最高到最低
const > ref > ref_or_null > range > index > all
我们可以通过 EXPLAIN 来查看sql的执行的访问方法,其中type列就是所使用的访问方法比如
EXPLAIN SELECT line_item_id from task_center;
创作不易,点个赞或者加个收藏吧~👍
最后的最后送大家一句话
白驹过隙,沧海桑田
与君共勉
文章持续更新,可以关注下方公众号或者微信搜一搜「 最后一支迷迭香 」第一时间阅读,获取更完整的链路资料。