一、一个复杂的查询,切分为多个简单的查询
有线程连接池,所以,不会存在连接断开和重连的开销。
一般网络很强大,多次数据传输速度会很快。
多个简单的查询可以充分利用缓存,mysql的查询缓存也好,服务端的缓存也好,特别是有架构引入了缓存组件的时候,更应该切分简单的查询,包括后面的高扩展性方面,简单查询更容易对数据库拆分,做高扩展。
当然,并不绝对,按业务和实际情况,分析。
再比如,delete删除几十万甚至上百万数据,可以切分为多次删除,每次删除后还可以暂停一会再执行删除,一次减少锁竞争,而是让压力分散。
二、数据库执行查询的流程
1.客户端发送一条sql给服务器。
2.服务器查询这条sql有没有查询缓存,有则直接返回。
3.没有查询缓存,则sql解析器对sql进行解析、预处理器预处理、由优化器生成执行计划。
4.按照执行计划调用存储引擎api执行查询。
5.将结果返回客户端。
三、查询状态
show full processlist,可以看到所有连接线程以及线程状态,值得说明的是,
线程状态有:sleep,query,locked,而locked说明正在等待表锁,行锁不会显示这个状态。
四、排序
如果待排序的量,小于排序缓冲区,则使用内存进行“快速排序”,否则,会将数据分块,每块独立“快速排序”,各个排序的结果存在磁盘上,最后进行合并。
mysql有两种排序算法:
两次传输排序(旧版本):
第一次:读取行指针和需要排序的字段,进行排序,排序好了之后。
第二次:再根据行指针,读取行数据。
两次传输排序,因为进行两次io,所以性能低,但是排序的时候,只读取了待排序字段,能充分利用排序内存。
单次传输排序(新版本):
读取所需要的所有列,包括所需的列,排序的列。然后直接排序,直接返回给客户端。
优点是:只进行了一次io。
缺点是:查询了列也占用了排序内存。
mysql有一个参数:max_length_for_sort_data,控制是否使用单次排序还是两次排序。
对于join连接查询的排序:
如果排序的字段都来自第一个表,则会关联处理第一个表的时候,就对第一个表进行排序,之后再进行连接,所以explain的时候extra字段显示的是:use filesort或者use index。而如果来自于不同的表,则需要先进行关联,然后把结果存在临时表,再进行排序,如果还要进行limit,也是再排序之后进行limit,所以explain的时候,extra显示use temporary;use filesort。所以性能消耗很大。
mysql5.6有一定的优化,不会排序所有后进行limit,而是抛弃掉不满足的数据,然后排序。
五、关于子查询
书上说,使用in 子查询,explain查看执行计划的时候,会显示变成了exisit,其实新版本不会。而且,说尽量使用连接查询而不用子查询,我觉得现在得新版本不存在这个问题。
但是 in、exisit还是使用连接查询,这个得根据实际业务来说。
比如 in里面得数据太大,则使用exisit,而比如前面说得延迟查询利用覆盖索引,在不能使用in查询,只能使用连接查询。
explain select * from article a where a.id in (select id from article order by title limit 1000, 10)
This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
六、对同一个表得查询更新操作
对同一个表同时进行更新查询操作,会报错
update test t set t.sex = (select count(*) from test b where t.`name` = b.`name`) ;
You can't specify target table 't' for update in FROM clause
可以优化为
update test t left join (select count(*) ct, name from test b group by b.`name`) ab
on t.`name` = ab.name set t.sex = ab.ct;
七、尽量避免使用for update 锁记录
首先是并发性不好,然后一般都可以找到其他得路径替代这个方式。
网友评论