共计 1874 个字符,预计需要花费 5 分钟才能阅读完成。
后面几篇文章和小伙伴们聊的基本上都是从索引的角度去优化 MySQL 查问,然而,索引创立的好,并不意味着查问就肯定快,影响查问效率的因素特地多,明天咱们就来聊一聊这些可能影响到查问的因素。
1. 查问流程
开始明天的内容之前,先来和小伙伴们大略捋一捋 MySQL 的查问流程。咱们来看如下一张图:
- 首先,用户通过连接器和服务端之间建设通信连贯,这个说白了就是一个 Socket 通信,用户名 / 明码的校验,用户权限的判断等等,都是在这个连接器中实现的。
- 接下来须要对我么传入的 SQL 进行解析,这块跟代码的执行流程其实差不多,先做词法剖析,辨认出各种关键字,而后再做语法分析,语法分析就是依据 MySQL 的各种语法规定,去判断 SQL 是否满足语法规定。
- 接下来就是查问优化器出场,查问优化器就是剖析要执行的 SQL,判断应该抉择哪一个索引,包含在多表联结查问的时候,各个表的连贯程序也是由查问优化器来决定的,优化器执行结束之后,会生成查问执行打算,咱们平时通过 explain 关键字查看到的就是这个。
- 最初就是执行器了,执行器调用搜索引擎提供的具体接口去获取数据。
这张图大家大略有个印象,在后续的 MySQL 查问和优化中,很多货色就容易了解了。
接下来咱们就来看看什么状况下查问会变慢。
2. 查问了不须要的记录
数据按需取用。有时候咱们会疏忽多拿数据对查问性能的影响,然而优化是一个斤斤计较的事件,须要多少数据就查问多少,要尽量避免数据库查问 100 条,后果前端只展现 10 条这种状况。如有须要,能够通过 limit 来限度数据库查问进去的数据总量。
如果在查问的时候应用了唯一性索引的话,那么查问到记录之后 MySQL 就进行扫描了;然而如果查问的时候应用的是非唯一性索引的话,那么扫描到第一条记录之后,还会持续向后扫描,直到扫描到第一条不满足条件的记录为止,对于这种状况,如果咱们确定查问的后果只有一条,则能够通过 limit 进行限度,设置 limit 1,那么扫描到第一条满足条件的记录之后,就不会持续扫描了。
3. 返回须要的列
查问的时候尽量避免 select *
,这个问题在之前的文章中松哥其实和大家聊过了,因为很多时候咱们在前端其实并不需要应用到那么多字段,可能只是为了查问简略,间接来一个 select *
,有时候列数和数据总量都比拟少的时候,这么写也看不出来性能显著的差别,然而当列数和数据量大了,那么 select *
带来的影响就会比拟大了。
特地是有的时候多表联结查问,如果用 select *
就会把多张表的查问后果拼接到一起,那么此时查问后果的列数就会成倍增加。
在后面的文章中,松哥也和大家提到过笼罩索引,如果索引设计切当,那么在查问的时候能够通过笼罩索引来进步查问的性能,然而如果应用了 select *
那么大概率是用不了笼罩索引了。
4. 恰到好处的缓存
这里举一个 TienChin 我的项目的例子,用户登录胜利之后,在后续的流程中,常常会用到以后登录用户的信息,如果每次都去数据库查问,每次查问返回后果都是统一的,没有必要,此时咱们能够将用户信息存入到 Redis 缓存中,须要的时候从 Redis 中提取就能够了。
在我的项目中,对于这些须要屡次频繁查问,且每次查问返回后果一样的数据,都能够抉择将之存入到缓存中以进步查问性能。
5. 关注扫描行数
在查问的时候,咱们能够通过 explain 来查看执行打算,执行打算中有一个指标是扫描行数,如下图中的 rows,这个就示意查问优化器预估要扫描多少行记录,filtered 则示意预估满足条件的比例。
个别在单表查问时候咱们并不会特地关注 filtered 字段,在多表联结查问的时候会比拟关注该字段的值。
6. 关注扫描类型
这一条实际上就是让大家关注后面查问打算中的 type 字段的值,type 字段的取值有很多种,例如常见的 index、ALL、range、const 以及 ref,还有一些不常见的如 system、eq_ref、fulltext、ref_or_null、index_merge、unique_subquery、index_subquery 等,每一种都代表了不同的查问打算,再联合查问打算中的 Extra 字段中的值,咱们大抵上能够将查问分为三种类型:
- 间接调用存储引擎层进行查问,查问后果在 MySQL Server 层不须要额定解决,间接返回给客户端即可。
- 间接从索引中过滤出来想要的值并返回给客户端,这种时候,过滤尽管产生在 MySQL Server 层,然而因为不须要回表,效率也还过得去。
- 从数据表中查问到相应的记录,而后在 MySQL Server 层进行过滤,过滤的同时可能还须要回表,此时效率就会低一些。