mysql的访问方法概念
mysql在执行我们的sql语句的时候,会经过查询优化器
将我们的sql语句进行优化,然后采用最小的查询成本来执行我们的sql。
mysql可以采用的查询方式有以下几种
- 采用全表扫描的方式来进行查询
- 使用索引进行查询
- 使用主键索引或者唯一二级索引进行等值查询
- 使用普通二级索引进行等值查询
- 针对索引列进行范围查询
- 遍历整个索引进行查询
mysql在执行查询语句的时候,可能会采用多种查询方式进行查询,当然mysql会计算多种查询方式查询成本,采用最优的方式来进行查询
建立索引
常见的几种访问方式
system
表只有一行记录(等于系统表),这是const类型的特列,平时不会出现,这个也可以忽略不计
const
const 意思是常数级别的,代价是可以忽略不计的。不过这种const访问方法只能在主键列或者唯一二级索引列和一个常数进行等值比较时才有效,如果主键或者唯一二级索引是由多个列构成的话,索引中的每一个列都需要与常数进行等值比较,这个const访问方法才有效(这是因为只有该索引中全部列都采用等值比较才可以定位唯一的一条记录)
# key2为唯一索引
SELECT * FROM single_table WHERE key2 = 3841;
# 查询null
SELECT * FROM single_table WHERE key2 IS NULL;
ref
ref
的查询方法大致的步骤是,针对于普通二级索引,先通过普通二级索引定位到符合条件的二级索引的对应的主键ID,然后在通过主键ID去聚簇索引中查询对应的数据。
ref的查询方法和const的区别是,通过二级索引查询时,可能会查询到多个符合条件的二级索引的值,然后在分别回表查询。当查询到的数据比较多时,回表查询的代价也是比较大的
二级索引列值为null的情况
不论是普通的二级索引,还是唯一二级索引,它们的索引列对包含NULL值的数量并不限制,所以我们采用key IS NULL这种形式的搜索条件最多只能使用ref的访问方法,而不是const的访问方法。
对于联合索引这种二级索引来说,只要最左边的连续索引列与常数进行比较,就有可能使用到ref的访问方法,类似于我们常讲的最左匹配原则
ref_or_null
ref_or_null
这种访问方法适用于我们不仅想找出某个二级索引列的值等于某个常数的记录,还想把该列的值为null
的记录一起查出来,当使用二级索引进行查询而不是全表扫描的时候,这种访问方法就是ref_or_null
SELECT * FROM single_table WHERE key1 = 'abc' OR key1 IS NULL;
range
上面几种访问方式都是索引列与某一个常数值进行等值比较时的访问方法。如果我们的查询是针对于索引进行范围查询的话,我们除了可以采用回表查询的方式,也有可能会用到二级索引+回表
的查询方式进行查询。
SELECT * FROM single_table WHERE key2 IN (1438, 6328) OR (key2 >= 38 AND key2 <= 79);
上面这个查询,就涉及到了索引的范围查询。
所以,range
这种访问方式,就是值利用索引进行了范围匹配。
索引可以是聚簇索引也可以是二级索引
index
SELECT key_part1, key_part2, key_part3 FROM single_table WHERE key_part2 = 'abc';
分析下上面的这个查询语句,查询的三个字段我们已经建立的联合索引,但是where的条件中只有联合索引中间的 key_part2
,我们知道针对于联合索引的等值查询,如果符合最左匹配原则的话,那么是可以采用ref
的访问方式的。但是目前的where条件不符合最左原则,所以不能采用ref
的访问方式。
因为我们对所要查询的字段key_part1
,key_part2
,key_part3
建立了二级索引,所以尽管不符合最左原则,但是我们可以直接通过遍历二级索引,然后在二级索引中找出符合查询条件的记录,这样也不需要回表查询,直接通过遍历二级索引的方式就能查询到我们想要的数据。这种访问方式叫做index
。
采用index
的这种访问方式,虽然我们遍历了二级索引,但是二级索引比聚簇索引要小的多。
all
all
这种访问方式通过名字我们也能看出来,这种就是全表扫描的查询方式了。
查看sql的访问方法
我们可以通过查看sql的执行计划来查看sql的具体采用了那种访问方式
# 在udc_company表中,ID为主键索引
EXPLAIN SELECT * FROM udc_company WHERE ID='2b6e4413-e29e-5fd9-82b8-13694634f9c6'
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ltRZugiA-1664257518448)(evernotecid://3FF987EF-EC0D-4AE0-B527-B88DFA6E477C/appyinxiangcom/26972899/ENResource/p320)]
我们通过查看查询计划,可以看到对于主键索引的等值查询,查询的type
就是const
EXPLAIN执行计划结果解析
通过explain我们可以获得以下信息:
- 表的读取顺序
- 数据读取操作的操作类型
- 哪些索引可以使用
- 哪些索引被实际使用
- 表之间的引用
- 每张表有多少行被优化器查询
下面就来逐个认识一下
id
select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序
例如下面这个sql
EXPLAIN SELECT * FROM reconc_proforma_line WHERE proforma_id =(SELECT ID FROM reconc_proforma WHERE id='000b3d8a-c071-40d1-a575-83a60ec2522c')
当ID相同时,对于多个sql语句的查询会从上到下的顺序依次执行
当sql中有自查询的时候,ID的数字就可能会有不同,此时id 数字越高,查询的优先级越高
- 多个ID相同的情况说明
EXPLAIN SELECT rp.*,rpl.* FROM reconc_proforma rp,reconc_proforma_line rpl WHERE rp.id='000b3d8a-c071-40d1-a575-83a60ec2522c' and rpl.id='57530f19-8f82-4067-bda8-14d984d51c31'
看下结果
结果中ID都为1,所以执行顺序从上到下
select_type
select_type
主要用来区别普通查询、联合查询和子查询等复杂查询的情况
其主要包含以下几个值:
- SIMPLE 简单的select查询,查询中不包含子查询或者UNION
- PRIMARY 查询中若包含任何复杂的子部分,最外层查询则被标记为PRIMARY
- SUBQUERY 在SELECT或WHERE列表中包含了子查询
- DERIVED 在FROM列表中包含的子查询被标记为DERIVED(衍生),MySQL会递归执行这些子查询,把结果放在临时表中
- UNION 若第二个SELECT出现在UNION之后,则被标记为UNION:若UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED
- UNION RESULT 从UNION表获取结果的SELECT
table
table
就比较简单了,指的就是当前的记录所查询的表
partitions
如果查询是基于分区表的话,会显示查询将访问的分区。
type
type
就是展示当前sql采用哪种访问类型进行访问查询。常见的类型有:system
const
ref
ref_or_null
range
index
all
possible_keys
possible_keys 显示可能应用在这张表中的索引,一个或多个。查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用。
key
实际上使用到的索引,如果key
的值为null,则代表没有使用索引或者没有建立索引
key_len
表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度,在不损失精确性的情况下,长度越短越好。key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的。
ref
这一列显示了在key列记录的索引中,表查找值所用到的列或常量,常见的有:const(常量),字段名等。一般是查询条件或关联条件中等号右边的值,如果是常量那么ref列是const,非常量的话ref列就是字段名。
rows
根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数,也就是说,用的越少越好
filtered
这一列是MySQL 5.1里新加的,它显示的是针对表里符合某个条件(where子句或联结条件)的记录数所做的一个悲观估算的百分比
extra
这一列展示一些额外的信息
下面介绍一下我们常见的几种情况
- Using index:使用覆盖索引,结果集的字段是索引,如果同时出现了Using Where表明索引用来查找健值,如果没有出现Using Where则表示索引用来直接读取数据,而不是查找键值
- Using index condition:查询的列不完全被索引覆盖
- Using where: 查询的列未被索引覆盖,使用了where条件过滤
学习了这些,能帮助我们对sql进行优化。