琢磨一个角色权限案例想到的分解关联查询问题

208 阅读4分钟

本文正在参加「技术专题19期 漫谈数据库技术」活动

学习数据库,最初琢磨的总是如何掌握跟多的语法,更多的函数,更多的触发器,等到掌握一些后,开始忐忑,我的查询到底是不是最优的,到底是不是最快的,到底是不是最省的.......,那么我们来聊一聊为啥查询会变慢,这里要提前强调的是,我们聊的是为啥查询会变慢,而不是数据库的优化,这两个还是有本质的区别的。

思考

首先我们在思考这个问题之前,先必须树立一个观念,就是说查询是一个任务,在他当中是一系列子任务,每个子任务执行都需要时间,那么总体加起来就是查询的时间,有了这个想法之后,我们就可以琢磨这么去优化了:

1、消除一些子任务

2、减少子任务执行时长或者次数

一次查询当中可以有很多子任务,我们很难一次性的包括所有,但是可以通过一个查询的生命周期来理解和掌握子任务,大致上说一个查询可以看成从客户端,到服务端,然后服务端解析请求,服务端生成执行计划,执行操作,返回结果给客户端几个生命周期,每个周期当中都会有很多子任务,其中执行应该是这个过程当中最为重要的阶段,这个阶段包含了大量的为了检索数据到存储引擎的调用和调用后的处理,比如,分组,排序等等。

当然这里只是聊了一个部分概念,因为查询还会受到网络,CPU性能,生成统计信息,执行计划,锁等操作的影响。

上面大体的概述了一下我们这次优化的原理,还是需要说一声对于一个完整的查询生命周期,我们上面的说法还是太粗略了,这个之后我们讨论,这次我们只是基于这个理念来考虑哪些我们查询过程当中不必要的额外操作。

额外操作

个人感觉,查询数据库要做到足够的吝啬,能少查就少查,能不查就不查,下面我们聊聊常犯的错误:

查询额外的记录

查询之前,还是要过一下脑子,认真考虑一下我们需要那些数据,这些数据的共性是啥,是不是要查询所有语句,所以新手时候就要注意多使用limit语句,比如查询用户名为admin的用户:

#查询1
select username,password from user username = "admin"; #查询2
select username,password from user username = "admin" limit 1; 

大家仔细品品,尽管我们都知道username是唯一的,但是如果按照查询1来看,也是全表查询,但是查询2在查到1条数据之后就结束了,那么是不是一种节省。

查询额外的列

个人觉得这是特别不好的一种习惯,尤其新手一定要注意,当然这个大家已经强调过很多次了,但还是要对每一个select * 提高警惕:

#bed
select * from student;
​
#good
select name,age,gender from student;

当然多表联查更是如此,千万不要害怕麻烦,一次全查。

查询相同的记录

这个是对业务层面说的,比如,在我们编写电商网站的时候,商品的图片,在轮播,详情部分都会需要,如果业务允许是不是可以查询一次,多次使用,能少查就少查一些。

评估

那这么去评估我们的这些额外操作呢,我们可以通过三个维度:

响应时间

响应时间在我们查询结束后是会返回的,但是我们稍微仔细考虑,一个查询的响应时间应该有两个部分:

服务时间:服务时间很好理解,就是服务器处理这个查询许哟啊的时间

排队时间:由于服务器等待资源导致没有执行查询的等待时间,这个等待可能包括I/O,锁等等。

所以在评估效率的时候要考虑是什么应用类型的查询,如果有存储引擎的锁,高并发竞争,硬件响应这些,自然查询会慢写,当然优化和考虑也就需要从这些方面进行侧重了。

扫描行数和返回行数

这个可以理解为一种性价比,和我们上面强调的额外记录,额外列有交集,加入一次查询返回了1行,但是扫描了100行,那么就要考虑是不是可以在扫描10行的情况下得到这1行。

这篇文章就简单的聊这些,有不足的地方还请大家多多指教。

本文正在参加「技术专题19期 漫谈数据库技术」活动