美文网首页
高性能mysql-查询性能优化(三)

高性能mysql-查询性能优化(三)

作者: 无聊之园 | 来源:发表于2019-05-23 15:37 被阅读0次

    一、一个复杂的查询,切分为多个简单的查询

    有线程连接池,所以,不会存在连接断开和重连的开销。
    一般网络很强大,多次数据传输速度会很快。

    多个简单的查询可以充分利用缓存,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 锁记录

    首先是并发性不好,然后一般都可以找到其他得路径替代这个方式。

    相关文章

      网友评论

          本文标题:高性能mysql-查询性能优化(三)

          本文链接:https://www.haomeiwen.com/subject/yjnvzqtx.html