1.为什么查询速度会慢
2.慢查询基础:优化数据访问
1.查询性能低下最基本的原因是访问的数据太多,大部分性能低下的查询都可以通过减少访问的数据量的方式进行优化。
2.是否向数据库请求了不需要的数据,有些查询会请求实际需要的数据,然后这些多余的数据被应用程序
(1)查询不需要的数据:常常会误以为MySql会只返回需要的数据,实际上MySql却是先返回全部结果集再进行计算
(2)多表关联时返回全部列:
(3)总是取出全部列
select * 取出全部列,会让优化器无法完成索引覆盖扫描这类优化,而且会为服务器带来额外I/O等消耗。
(4)重复查询数据
3.是否在扫描额外的记录
(1)查询类型
删除对应索引,访问类型变成了一个全表扫描(ALL),现在MySql预估需要扫描5073条记录来完成这个查询。这里“Using Where" 表示MySql将where条件来筛选存储引擎返回的记录
(2)应用Where条件方式-三种 从好到坏
索引中使用where条件过滤
覆盖索引中过滤Using index
数据表中返回数据,过滤不满足条件的记录Using Where
(3)理解一个查询需要扫描多少行和实际需要使用的行数需要先去理解这个查询背后的逻辑和思想
(4)如果发现查询需要扫描大量的数据但只返回少数的行,那么通常可以尝试下面技巧去优化
-- : 使用覆盖索引,把所有需要的列都放到索引中,无需回查表
-- : 改变库表的结构
-- : 重写查询语句
3.重构查询的方式
1.一个复杂查询还是多个简单查询
(1)MySql从设计上让连接和断开连接都很轻量级,在返回一个小的查询结果方面很高效。
(2)如果一个查询能够胜任时还写成多个独立查询是不明智的。
2.切分查询
(1)一次删除大量数据会锁住表,分开多次 limit 1000
3.分解关联查询
(1)例如:
优势:
-- : 让缓存效率更高:有些应用程序使用缓存数据,刚好有对应数据。则跳过第一条
-- : 单个查询可以减少锁的竞争
-- : 减少冗余记录的查询,在应用层做关联查询
4.查询执行的基础
1.执行流程
2.MySql客户端/服务器通信协议
(1)MySql通信协议是半双工的,这意味着在任何一个时刻,要么由服务器向客户端发送数据,要么由客户端向服务器发送数据,两个动作不能同时发生。
5.MySql查询优化器的局限性
1.关联子查询
定义:
-- : 引用外部的一列或多列
-- : 将外部查询的每一行都传递给子查询,子查询依次读取传递过来的每一行的值,并将其使用到子查询上,直到外部查询的所有行都处理完为止,然后返回子查询的结果
(1)例:Where条件中包含IN()的子查询语句
(2)因为MySql对IN()列表中的选项有专门的优化策略。MySql会将相关的外层表压到子查询中,它认为这样可以更高效地查找到数据行。My会将查询改写为下面的样子:
(3)因为需要film_id字段,所以MySql认为无法先执行这个子查询。通过Explain可以看出先遍历外表查询再执行内表查询。‘
(4)因为使用in()加子查询,性能经常会非常糟,所以通常建议使用Exinsts()等效的改写查询来获取更好的效率
2.如何用好关联子查询
(1)例子:
(2)一般会建议使用左外连接(left outer join)重写该查询,以代替子查询。
2. UNION的限制
(1)例子:将两个表的记录存储到中间表中
(2)修改:减少中间表中的数据
3.索引合并优化
(1)当where子句中包含多个复杂条件的时候,MySql能够访问单个表的多个索引以合并和交叉过滤的方式来定位需要查找的行。
4.在同一个表中查询和更新
(1)例子:
(2)优化:可以通过生成表来绕过上面的限制
6.查询优化器的提示
7.优化特定类型的查询
1.count(*)
(1) 当我们使用count(*)的时候,这种情况通配符*并不会扩展成所有的列,实际上,它会忽略所有的列而直接统计所有的行数.。如果希望知道的是结果集的行数,最好使用count(*)。意义清晰,性能也会很好。
2.关联查询
(1)在创建索引的时候就要考虑到关联的顺序。当表A和表B用列c关联的时候,如果优化器的关联顺序是B,A。那么就不需要在B表的对应列上建上索引。
3.优化子查询
(1)尽可能使用关联查询代替。如果使用的是MySql5.6或更新版本,可以忽略。
4.优化limit分页
(1)当偏移量非常大的时候,例如1000,20这样的查询。需要访问前1020条数据。
(2)最简单的办法就是尽可能地使用索引覆盖扫描,而不是查询所有的列。然后根据需要做一次关联操作再返回需要的列。对于偏移量很大的时候,这样做的效率提升非常大。
select film_id ,description from sakila.film order by title limit 50,5 ;
表非常大,改写为:
select film.film_id,film.description from sakila.film inner join (select film_id from sakila.film order by title limit 50,5) as lim using(film_id);
5.优化UNION查询
(1)UNION 相对于 UNION ALL。如果没有ALL关键字,MySql会给临时表加上DISTINCT选项。导致对整个临时表的数据做了唯一性检查。这样做代价非常高。