第6章 查询性能优化
- 查询会慢的原因通常是以为存在着的各种子任务,优化查询实际上是优化子任务。
- 将一个大查询切分成多个小查询可以减少锁的持有时间,有效利用缓存,更可扩展,当同时会带来带宽和数据传输的消耗,要自己权衡利弊。
查询执行流程
- 客户端发送一条查询给服务器。
- 服务器先检查缓存,如果命中返回查询结果,否则下一阶段。
- myql对SQL解析 ,预处理,再由优化器生成对应的执行计划。
- MySQL根据优化器 生成的执行计划,调用存储引擎的 API来执行查询。
- 可能缓存结果,返回数据给客户端。
- Mysql在传输过程是半双工的方式传输的,如果客户端发送了 查询,接下来它能做的只有等待了,当服务端开始响应 ,客户端必须完整地接收整个返回结果,客户端像是“从消防水管喝水”
连接的查询状态
- Sleep:正在等待客户端发送新的请求。
- Query:现在正在查询或者正在将结果发送给客户端。
- Locked:线程正在等待锁。
- Analyzing and statistics:
- Copying to tmp table[on disk]:正在将结果复制进临时表。
- Sorting result:排序中
- Sending data:线程可能在多种状态之间传送数据。
- 能否命中缓存是通过对一个大小写敏感的哈希查找的。命中缓存之后还会看看该查询是否满足条件。
- 在mysql中IN和多个OR并不等价,MySQL中的IN()列表中的数据会先进行排序,然后通过二分查找的方式来确定列表中的值是否满足条件。
- 数据和索引的统计信息可以帮助影响到优化器。
- 在mysql中,所有的查询都是关联查询,连单表查询也是,执行策略很简单,先在一个表中循环取出单条数据再嵌套循环关联操作,即MySQL先在一个表中循环取出单条数据,然后再嵌套循环到下一个表中寻找匹配的行,如此循环。
- 临时表是没有任何索引的。
- 无论如何排序都是一个代价很高的操作。当不能用索引排序的时候,需要自己排序,数据量小在内容进行,如果数据量大就要用到磁盘了。
- 有时候在排序的时候,使用的临时空间可能比想象中的要大很多,因为会分配一个足够长的定长空间来存放。使用Limit,对排序也有优化效果。
- 结果返回给客户端并不是全部查询出来才返回,而是产生第一条数据就开始返回给客户端了。
- 关联查询不一定会比子查询快,要有自己的判断。
- 等值传递:如果发现查询中有其它的WHERE,ON或者USING的子句,会将条件复制到应用关联的表中,但是万一条件非常长,会导致优化和执行变慢。
- mysql5.6并不支持多核特性来并行执行查询。
- MySQL并不支持跳跃索引查询,所以当查询条件是b的时候是无法使用(a,b)索引的。
- 如果对优化器选择的执行计划不满意,可以使用优化器提供的几个提示来控制最后的执行计划。
- COUNT如果指定了列,那么统计的就是该列的非空值的数量。
- 在不要求最精确的COUNT的时候,用EXPLAIN也是个不错的选择。
- 优化关联索引:确保ON的列上有索引,但是要注意被关联的表有可能是不需要关联列的索引的;确保GROUP BY和ORDER BY只涉及到其中一个表中的列。
- 利用覆盖索引+延迟关联能优化LIMIT很后面的查询,因为这样让MySQL扫描了尽可能少的页面。如果知道了边界值,用between也是个不错的选择。
- 编写UNION查询,如果找到了就提前返回:
SELECT GREATEST(@found := 1, id) AS id ,'uesrs' AS which_tb1
FROM users where id = 1
UNOIN ALL
SELECT id , 'users_archived' FROM users_archived WHERE id = 1 AND @found IS NULL
UNOIN ALL
SELECT 1, 'reselt' FROM DUAL WHERE ( @found := NULL ) IS NOT NULL;