如何使用ORDER BY子句增加和降低性能?

时间:2014-04-11 15:07:37

标签: mysql performance innodb database-performance

我有一个名为devicelog的MySQL表,其id上有PK,但device_id(INT),field_id(INT)和unixtime上有多个索引(BIGINT) )。它们只是默认的InnoDB索引。

我试图在一定时间内获取ID,我得到不同的性能与不同的值和不同的ORDER BY。 ID和unixtimes都有正关联,因为随着更多数据的插入,它们都在增加,所以似乎可以安全地省略unixtime上的排序。我的表有大约2500万条记录,性能非常重要。

此查询相当慢(~0.5秒):编辑:使用USE INDEX(unixtime)后,我能够提高性能(<0.01秒!)。

SELECT 
    id
FROM
    devicelog
USE INDEX(unixtime) /* edit: looking at the EXPLAIN, I can use this index and it sped things up a bit */
WHERE
    device_id = 26
        AND field_id = 64
        AND unixtime >= 1397166634707 /* a fairly recent time */
/* with no ORDER BY clause, this query is surprisingly slow */
LIMIT 1

说明:

1, SIMPLE, devicelog, index_merge, device_id,field_id,field_id_2,unixtime, field_id,device_id, 8,8, , 6667, Using intersect(field_id,device_id); Using where

此查询非常快(<0.01秒):

SELECT 
    id
FROM
    devicelog
WHERE
    device_id = 26
        AND field_id = 64
        AND unixtime >= 1397166634707 /* a fairly recent time */
ORDER BY unixtime ASC                 /* <- using unixtime to order */
LIMIT 1

说明:

1, SIMPLE, devicelog, range, device_id,field_id,field_id_2,unixtime, unixtime, 9, , 897776, Using index condition; Using where

如何省略ORDER BY会降低性能?认为它会提高速度似乎是合乎逻辑的。

然而,如果我将unixtime更改为远程返回到“1”,当我使用ORDER BY unixtime时它会完全变慢。我相信unixtime索引是按升序排序的,所以这也没有多大意义。

此查询的执行方式与上述查询相反。

非常快(<0.01秒):

SELECT 
    id
FROM
    devicelog
WHERE
    device_id = 26
        AND field_id = 64
        AND unixtime >= 1 /* a long time ago */
LIMIT 1

说明:

1, SIMPLE, devicelog, index_merge, device_id,field_id,field_id_2,unixtime, field_id,device_id, 8,8, , 6742, Using intersect(field_id,device_id); Using where

此查询与快速查询完全相同,只是它使用较旧的时间:

非常缓慢(约7秒):

SELECT 
    id
FROM
    devicelog
WHERE
    device_id = 26
        AND field_id = 64
        AND unixtime >= 1         /* a long time ago */
ORDER BY unixtime ASC             /* <- using unixtime to order */
LIMIT 1

说明:

1, SIMPLE, devicelog, index, device_id,field_id,field_id_2,unixtime, unixtime, 9, , 3504, Using where

有没有人对广泛的性能差异有任何见解?

2 个答案:

答案 0 :(得分:1)

我认为这是LIMIT优化的记录行为,请参阅http://dev.mysql.com/doc/refman/5.5/en/limit-optimization.html

  

优化LIMIT查询

     

MySQL有时会优化具有LIMIT row_count子句且没有HAVING子句的查询:

     

[...]   如果将LIMIT row_count与ORDER BY一起使用,MySQL会在找到排序结果的第一行row_count行后立即结束排序,而不是对整个结果进行排序。如果使用索引完成排序,则速度非常快。如果必须完成文件排序,则在找到第一个row_count之前,将选择与没有LIMIT子句的查询匹配的所有行,并对其中的大部分或全部进行排序。在找到初始行之后,MySQL不会对结果集的任何剩余部分进行排序。

     

[...]

     

只要MySQL向客户端发送了所需的行数,它就会中止查询,除非您使用的是SQL_CALC_FOUND_ROWS。

因为您试图在特定日期旁边获取ID,我认为排序结果非常重要,因为否则您可以获得任意值。否则,您必须根据条件使用MIN(id)来获得所需的id值。

答案 1 :(得分:1)

如果不知道表格中的行数以及表格的确切结构,很难就性能提出明确的建议。

您可以在(unixtime, device_id, file_id, id)上尝试覆盖索引的复合词。 (如果你不知道那个词,请查看索引索引。)

这将允许您的查询的unixtime部分满足BTREE查找,然后通过索引扫描可以满足您的查询的其余部分。

如果您指定ORDER BY unixtime ASC LIMIT 1,则告诉查询引擎停止扫描该索引(一旦获得一次点击,就会unixtime排序。

我不知道为什么当你省略ORDER BY时它有时会继续扫描七秒钟。它可能需要寻找匹配的device_idfile_id值。