美文网首页@IT·互联网程序员
排序导致服务器宕机

排序导致服务器宕机

作者: 数据运营python | 来源:发表于2017-05-01 22:10 被阅读1242次

    背景

    上线后,发现服务器的实例陆续挂掉,通过查看日志没有发现什么异常的地方,可以排除内存溢出的问题。查看数据库的show processlist 发现有一个sql锁住了。该sql 是最近一次才上线,通过对比两次上线的内容,发现这次是多了一个排序而已,怎么多了一个排序就导致服务器挂了。

    修改前:

    select * from table ORDER BY non_index_column limit 10;

    修改后:

    select * from table ORDER BY non_index_column ,index_column limit 10;


    explain

    首先先想到通过explain命令看一下这个sql是怎么执行,怎么会导致数据库锁住了。

    查询结果
    select_type
    1. SIMPLE :查询不包括子查询和UNION
    2. PRIMARY:查询有任何复杂的子部分,最外层部分标记为这个值
    3. SUBQUERY:select列表中的子查询
    4. DERIVED :表示包含在from子句的子查询的select
    5. UNION:在UNION中的第二个和随后的select 被标记为UNION
      6.UNION RESULT:用来从UNION的匿名临时表检索结果的select 被标记为union result
    table
    1. 通常是表示该行的表名或者别名
    2. 派生表和联合市以<derivedN>的形式,其中N表示子查询的id
    type

    这个是指 mysql如何查询表中的行,依次从最差到最优:

    1. ALL
      全表扫描

    2. index
      这个跟全表扫描一样,只是扫描的时候是按索引进行,而不是按行。它主要是避免了排序;如果是按随机次序访问行的话,开销会比较大。
      如果是在Extra列中看到“Using index”,说明正在使用覆盖索引,它只是扫描索引的数据,开销比按索引次序全表扫描的开销少很多。

    3. range
      范围扫描就是一个有限制的索引扫描,一般查询里面带between,或者>,< in,or 会显示这个。开销跟索引类型相当

    4. ref
      索引访问,索引跟某个参考值相比较,这个参考值或者是一个常数,或者是来自夺标查询前一个表里的结果值

    5. eq_ref
      使用这种索引查找,数据库知道最多只返回一条符合条件的记录。

    6. const,system
      当数据库能对查询的某部分进行优化并将其转换成一个常量时,就会使用这种类型

    7. NULL
      这种访问方式意味着数据库可以在优化阶段分解查询语句,在执行阶段设置用不着再访问表或者索引

    possible_keys

    着一列显示了查询可以使用哪些索引,这是基于查询访的列和使用的比较操作符来判断

    key

    显示数据库采用那个索引来优化对该表的访问。possible_keys 揭示了哪个索引能有助于高效的行查找。key显示的是优化采用哪一个索引可以最小化查询成本。

    key_len

    key_len列显示了在索引字段中可能的最大长度,而不是表中数据使用的实际字节数。

    ref

    这一列显示了之前的表在key列记录的索引中查找值所用的列或常量。

    rows

    这一列是数据库为了找到所需的行而要读取的行数,而不是结果集里面的行数。

    Extra

    这一列包含的是不适合在其他列显示的额外信息。

    1. Using index :数据库将使用覆盖索引,以避免访问表。
    2. Using where: 意味服务器将在存储引擎检索行后再进行过滤,暗示查询可收益于不同的索引。
    3. Using temporary:对查询结果排序时会使用一个临时表
    4. Using filesort:对结果使用一个外部索引排序,而不是按索引次序从表里读取行。
    5. Range checked for each record(index map:N):没有好用的索引,新的索引将在联接的每一行上重新估算。

    profiles

    前面两个语句执行后的结果都是“Using filesort”的,这个时候只能通过profiles分析一下sql的性能.

    type:  
        ALL                --显示所有的开销信息  
      | BLOCK IO           --显示块IO相关开销  
      | CONTEXT SWITCHES   --上下文切换相关开销  
      | CPU                --显示CPU相关开销信息  
      | IPC                --显示发送和接收相关开销信息  
      | MEMORY             --显示内存相关开销信息  
      | PAGE FAULTS        --显示页面错误相关开销信息  
      | SOURCE             --显示和Source_function,Source_file,Source_line相关的开销信息  
      | SWAPS              --显示交换次数相关开销的信息  
    
    查看设置

    SHOW VARIABLES LIKE '%pro%';

    查询结果
    打开开关

    set profiling=1;

    执行语句
    先清空缓存
    reset query cache;
    查看执行结果
    show profiles;
    查看某一条执行结果
    show profile for query 5;
    
    结果

    通过两个语句的性能比较,有2个字段进行排序的时间比一个排序的时间只是多了一点的,查看数据库的缓存:

    show variables like '%max_length_for_sort_data%';
    1024
    show variables like '%read_rnd_buffer_size%';
    16M
    

    order by limit 优化

    Order by和limit一起使用的优化原理
    从MySQL5.6.2版本以后,优化器将更加智能地处理下面形式的查询了
    
    SELECT ... FROM single_table ... ORDER BY non_index_column [DESC] LIMIT [M,]N;
    
    这种在很大的结果集中只返回很少的行数的查询类型在web应用中非常常见,比如
    
    SELECT col1, ... FROM t1 ... ORDER BY name LIMIT 10;
    
    SELECT col1, ... FROM t1 ... ORDER BY RAND() LIMIT 15;
    
    排序缓存有一个参数是sort_buffer_size,如果这个参数大小足够上面范例中的N行的排序结果集(如果M也被定义,那就是M+N行的结果集大小),那么服务器将会避免一个文件排序操作,使得排序完全在内存中完成。
    
    内存排序+limit原理
    1 扫描表,在内存中插入那些被选择排序的列的数据到一个排好序的队列中,比如order by col1,col2,则插入col1和col2列的数据。如果队列满了,则挤出排序在末尾的数据。
    
    2 返回队列中的前N行记录,如果M也被定义,则调到第M行开始返回后续的N行记录。
    
    文件排序+limit原理
    1扫描表,重复步骤2和3,直到表的结尾
    
    2选中这些行数直到排序缓存被填满
    
    3在排序缓存中写入第一个N行(如果M被定义,则M+N行)到一个排序文件中。
    
    

    结论

    两个语句都是用了临时文件进行排序的方式,该语句的查询频率比较高,由于只有一个排序的字段的内容只有几个值,而第二个语句是通过该字段,还有主键进行排序,造成这样的结果猜测:

    1. mysql内部进行优化的查询
    2. 由于该查询频率比较,每次查询多出的一百多毫秒变成压死骆驼的最后一根稻草。

    相关文章

      网友评论

        本文标题:排序导致服务器宕机

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