zoukankan      html  css  js  c++  java
  • 一次mysql 优化 (Using temporary ; Using filesort)

    遇到一个SQL执行很慢 SQL 如下:

    SELECT 
    	...
    FROM 
    	tableA 
    WHERE time >= 1492044535 and time <= 1492046335 GROUP by time, sourceName, serverSite,clientSite;
    

    SELECT 部分忽略没写,是因为通常SQL执行慢不会跟这部分有关系,至少我没见过。

    该语句非常简单,但是执行太慢。所以我们看一下执行计划

    执行计划有几个字段我们比较关注:

    type:range
    possible_keys:time
    key:time
    extra:using index condition; using temporary; using filesort
    

    type 代表连接类型。range是索引范围扫描的时候显示的类型。
    possible_keys 和 keys 是可用的索引以及实际的索引
    extra 比较关键,我们详细看一下这里的信息:

    filesort

    是说在排序的时候,没办法使用索引。比如我们这里用的索引是time,但group by 是 time, sourceName, serverSite,clientSite。Mysql有一点很重要是会默认按照group by排序。

    group by time, sourceName, serverSite, clientSite 
    

    order by time, sourceName, serverSite, clientSite
    

    开销其实区别不大。所以这里排序不但要按照time 还要按照其它几列

    解决办法

    加order by null 这样在group by的时候默认不排序,可以去掉filesort。 但实际测试发现还是慢,所以file sort不是性能关键。

    using tempoaray

    这里是说在mysql执行过程中产生了临时表。这个操作比较耗时间。mysql的文档列出了几种会产生临时表的语法,但和我们这里的情况都不相符合。倒是mariadb的文档,虽然不是很详细,但说明了我们的语句确实可能用到临时表

    A temporary table is created to hold the result. This typically happens if you are using GROUP BY, DISTINCT or ORDER BY.
    

    仔细分析一下也有道理,用索引查到数据后,你需要对这些数据分组。这个过程肯定是在一个数据集上操作的,那么这个数据集应该就是临时表了。不想要这个数据集的办法就是取消这个分组操作。我们只需要create一个联合索引

    time,sourceName,serverSite,clientSite
    

    这样一个索引可以通过time过滤,天然按照分组的顺序排序,就不用临时表了。

    同时可以在执行语句中加个force index强制执行这个索引。
    这样就没有using temporary这个操作了

  • 相关阅读:
    收集珠子
    压缩变换(程序设计)
    动态规划-树上dp-1757. 搜集钻石
    动态规划-1620. 收集硬币
    动态规划-状态压缩-707. 最优账户结余
    图-1400. 图的费马点
    数学-快速幂
    计算几何-5361. 圆和矩形是否有重叠
    图-搜索-dfs-739. 24点
    图-dfs-连通分量-旋转变换-804. 不同岛屿的数量II
  • 原文地址:https://www.cnblogs.com/kramer/p/6703750.html
Copyright © 2011-2022 走看看