一、查询优化
在编写快速的查询之前,需要清楚一点,真正重要的是响应时间,而且要知道在整个SQL语句的执行过程中每个步骤都花费了多长时间,要知道哪些步骤是拖垮执行效率的关键步骤,想要做到这点,必须要知道查询的生命周期,然后进行优化,不同的应用场景有不同的优化方式,不要一概而论,具体情况具体分析。
1、查询慢的原因
①、网络 ②、CPU ③、IO ④、上下文切换 ⑤、系统调用 ⑥、生成统计信息 ⑦、锁等待时间
2、优化数据访问
查询性能低下的主要原因是访问的数据太多,某些查询不可避免的需要筛选大量的数据,我们可以通过减少访问数据量的方式进行优化
确认应用程序是否在检索大量超过需要的数据
确认mysql服务器层是否在分析大量超过需要的数据行
是否向数据库请求了不需要的数据
--查询不需要的记录
我们常常会误以为mysql会只返回需要的数据,实际上mysql却是先返回全部结果再进行计算,
在日常的开发习惯中,经常是先用select语句查询大量的结果,然后获取前面的N行后关闭结果集。
优化方式是在查询后面添加limit
--多表关联时返回全部列
select * from actor inner join film_actor using(actor_id) inner join film using(film_id) where film.title='Academy Dinosaur';
select actor.* from actor inner join film_actor using(actor_id) inner join film using(film_id) where film.title='Academy Dinosaur';
--总是取出全部列
禁止使用select *,虽然这种方式能够简化开发,但是会影响查询的性能,所以尽量不要使用
--重复查询相同的数据
如果需要不断的重复执行相同的查询,且每次返回完全相同的数据,因此,基于这样的应用场景,
我们可以将这部分数据缓存起来,这样的话能够提高查询效率
3、执行过程的优化
3.1、查询缓存
在解析一个查询语句之前,如果查询缓存是打开的,那么mysql会优先检查这个查询是否命中查询缓存中的数据,如果查询恰好命中了查询缓存,那么会在返回结果之前会检查用户权限,如果权限没有问题,那么mysql会跳过所有的阶段,就直接从缓存中拿到结果并返回给客户端。
3.2、查询优化处理
3.2.1、语法解析器和预处理
mysql通过关键字将SQL语句进行解析,并生成一颗解析树,mysql解析器将使用mysql语法规则验证和解析查询,例如验证使用使用了错误的关键字或者顺序是否正确等等,预处理器会进一步检查解析树是否合法,例如表名和列名是否存在,是否有歧义,还会验证权限等等
3.2.2、查询优化器
mysql> use sakila;
Database changed
mysql> select count(*) from film_actor;
+----------+
| count(*) |
+----------+
| 5462 |
+----------+
1 row in set (0.19 sec)
mysql> show status like 'last_query_cost';
+-----------------+------------+
| Variable_name | Value |
+-----------------+------------+
| Last_query_cost | 558.199000 |
+-----------------+------------+
1 row in set (0.00 sec)
在很多情况下mysql会选择错误的执行计划,原因如下:
1.统计信息不准确
InnoDB因为其mvcc的架构,并不能维护一个数据表的行数的精确统计信息
2.执行计划的成本估算不等同于实际执行的成本
有时候某个执行计划虽然需要读取更多的页面,但是他的成本却更小,因为如果这些页面都是顺序读或者这些页面都已经在内存中的话,那么它的访问成本将很小,mysql层面并不知道哪些页面在内存中,哪些在磁盘,所以查询之际执行过程中到底需要多少次IO是无法得知的
3.mysql的最优可能跟你想的不一样
mysql的优化是基于成本模型的优化,但是有可能不是最快的优化
4.mysql不考虑其他并发执行的查询
5.mysql不会考虑不受其控制的操作成本
执行存储过程或者用户自定义函数的成本
3.3、优化器的优化策略
静态优化
直接对解析树进行分析,并完成优化
动态优化
动态优化与查询的上下文有关,也可能跟取值、索引对应的行数有关
mysql对查询的静态优化只需要一次,但对动态优化在每次执行时都需要重新评估
3.4、优化器的优化类型
重新定义关联表的顺序
将外连接转化成内连接,内连接的效率要高于外连接
使用等价变换规则,mysql可以使用一些等价变化来简化并规划表达式
优化count(),min(),max()
预估并转化为常数表达式,当mysql检测到一个表达式可以转化为常数的时候,就会一直把该表达式作为常数进行处理
索引覆盖扫描,当索引中的列包含所有查询中需要使用的列的时候,可以使用覆盖索引
子查询优化
等值传播
3.5、关联查询
MySQL Optimization Learning(一)
MySQL Optimization Learning(三)
不断学习才能不断提高!
生如蝼蚁,当立鸿鹄之志,命比纸薄,应有不屈之心。
乾坤未定,你我皆是黑马,若乾坤已定,谁敢说我不能逆转乾坤?
努力吧,机会永远是留给那些有准备的人,否则,机会来了,没有实力,只能眼睁睁地看着机会溜走。