查询优化 索引优化 库表结构优化
优化查询吗,实际上是优化其子任务。
优化查询:
1。消除子任务
2。减少子任务执行次数
3。让子任务运行的更快
查询性能低下最基本的原因是访问的数据太多。
(1)返回的结果
limit,避免返回不需要的数据(而不是返回全部结果集)
select * ?是否需要返回全部列?
(2)扫描的记录
衡量查询开销的三个指标:响应时间、扫描的行数、返回的行数
响应时间=服务时间+排队时间(IO/所等待等等)
扫描的行数,在一定程度上说明找到需要的数据效率高不高。
扫描的行数和访问类型
explain 里的type就是访问类型,如全表扫,索引扫,范围扫,唯一索引查询,常数引用等
索引让mysql以高效、扫描行数最少的方式返回需要找的记录
explain里的extra:using index 索引覆盖扫描,无需回表
using where 从数据表中返回记录,用where条件过滤。
mysql客户端/服务器通信协议是半双工的
max_allowed_packet:客户端往服务器发送查询语句(只使用一个数据包,而不是多个数据包),当查询语句很长的时候,这个参数很重要,否则服务器会拒绝接受更多的数 据并抛出错误。
mysql通常需要等所有的数据都已经发送给客户端才能释放这条查询所占用的资源
种种原因可以看出,返回的结果集不要太大
查询状态:show full proccesslist中的command列显示信息。
查询缓存,先通过hash值进行比较,通过的话再验证用户权限,因为被缓存的表的权限已经存放在当前缓存中了。
语法解析器解析语法,预处理器验证权限。
查询优化器将语法树转化成执行计划。
mysql使用基于成本的优化器
mysql依赖存储引擎提供的统计信息来评估成本。
mysql优化器在评估成本的时候并不考虑任何层面的缓存,它假设读取任何数据都需要一次磁盘IO。(感觉评估的很不准确啊)
计算代价时,mysql并不知道那些页面在内存中,那些页面在磁盘上。
静态优化,动态优化。
静态优化只需要做一次(不依赖于特别的值,即使使用不同的参数执行查询也不会变化。) 编译时优化
动态优化则在每次查询的时候都重新评估(与参数取值,查询上下文等都有关系。)。 运行时优化
当进行IN()查询操作时,mysql会将IN列表中的值排序,然后查找。
服务器层有优化器,但是没有统计信息。统计信息由存储引擎层实现。
mysql查询优化器在生成执行计划的时候需要向存储引擎获取相应的统计信息。
mysql对任何关联都执行嵌套循环关联操作。
关联查询优化
straight_join 关键字让mysql按照你认为的关联顺序执行
排序优化
不能使用索引进行排序时,统称为文件排序(filesort),即使完全是内存排序不需要任何磁盘文件也是如此。
排序缓冲区不足时,使用磁盘,分块排序。
两次传输排序 :读取行指针和需要排序的字段,对读取的字段进行排序,然后根据排序好的字段和指针回表,读取所需的数据行。
缺点是:需要进行两次数据传输,第二次读取的时候由于按照排序后的顺序读取,会产生大量随机IO。
优点是:在排序的时候存储尽可能少的数据,让排序缓冲区中容纳尽可能多的行数进行排序。
单次传输排序 :先读取查询所需要的所有列(即select 语句中from之前的列表),然后根据给定的列进行排序。最后直接返回排序结果。
优点是 :不需要再从数据表中读取,对于IO密集型操作效率高了很多。相比两次传输,只需要一次顺序IO,不需要随机IO。
缺点是 :需要返回的列非常多,非常大,会额外占用很多空间,但这些列队排序操作本身来说没有任何作用。因为单条排序记录很大,可能会有更多排休爱需要合并。
max_length_for_sort_data :当查询需要的所有列的总长度不超过这个值时,使用单次传输排序。
在关联查询的时候如果需要排序,mysql会分两种情况来处理 :
1. using filesort的情况
如果order by子句中的所有列都来自关联的第一个表,那么mysql会在关联处理第一个表的时候进行文件排序。
这样的话,在mysql的explain结果中可以看到extra字段会有 using filesort。
2.using temporary;usingfilesort的情况
除了上面第一种情况之外,mysql都会先将关联的结果存放到一个临时表中,然后再所有的关联都结束后,再进行文件排序。
这样的话,在mysql的explain结果中国可以看到extra字段会有 using temporary;using filesort。
查询优化器的提示:
high_priority 和low_priority 这两个提示只对表锁的存储引擎有效。
delayed 对insert和replace有效,数据先插入到缓冲区中然后立即返回给客户端,然后等待表空闲时落盘。
straight_join 放在select 关键字之后,让表按照出现的顺序关联
放在任何两个关联变中间,固定其前后两个表的关联顺序。
sql_small_result 和 sql_big_result 只对select有效,告诉group by或者distinct如何使用临时表及排序。是否会用到磁盘排序。
sql_buffer_result 将结果集缓存到临时表,尽快释放表锁,而不是将结果集传输到客户端之后才释放表锁。减少表锁的时间。代价是消耗服务端更多的内存。
sql_cache 和 sql_no_cache 是否将查询结果缓存到结果集缓存中。
use_index ignore_index force_index
optmizer_search_depth 当连接的表比较多,mysql会尝试各种连接方式以选取最优的执行计划,这会耗费很多资源和时间,为了防止mysql尝试太多执行计划,设置此参数,穷举执行计划是有个限度。可以调整。
优化特定类型的查询:
表关联时,如果group by 或者order by中的表达式只涉及一张表上的列,可以用索引优化。否则不行。
子查询尽量用关联查询优化,但也并非绝对。
group by 和 distinct 都可以用索引来优化,这是最有效的。否则只能用临时表或文件排序,可以使用sql_big_result或者sql_small_result提示。
用查找表的标识列分组的效率比较高。
如果没有通过order by字句显示的指定拍序列,当查询使用group by子句的时候,结果集会自动按照分组的字段排序。如果不关心结果集的顺序,而这种默认排序又导致了需要文件排序,可以使用order by null,让mysql不再进行文件排序。
优化limit分页大偏移量的时候,如10000,20,最好用索引覆盖扫描,而不是查询所有的列。然后根据需要做一次关联操作再返回所需的列。对于偏移量非常大的时候,这样的操作效率提升会非常大。
mysql总是通过创建并填充临时表的方式来执行union查询。
队列表: 尽量使用update代替先select for update再update的方法,因为事务提交的速度快,持有锁的时间就越短,大大减少竞争和加速串行执行效率。