2016-11-16 69 views
0

我有一个名为'活动'与50M +行表。如何优化此性能不佳的Mysql查询?

CREATE TABLE `activities` (
    `activity_id` bigint(20) NOT NULL AUTO_INCREMENT, 
    `id_of_contract` bigint(20) DEFAULT NULL, 
    `duration_s` int(11) DEFAULT NULL, 
    `timestamp_end` bigint(20) DEFAULT NULL, 
    `timestamp_start` bigint(20) DEFAULT NULL, 
    `id_of_room` bigint(20) DEFAULT NULL, 
    PRIMARY KEY (`activity_id`), 
    KEY `analyse` (`id_of_room`,`timestamp_end`,`timestamp_start`,`duration_s`), 
    ENGINE=InnoDB DEFAULT CHARSET=utf8; 

我有这样的要求:

select * 
    from activities 
    where id_of_room=3263 
     and timestamp_end>1471491882747 
     and timestamp_start<1479267882747 
     and duration_s>900 
    order by duration_s desc; 

的解释回报这样的:

id select_type table  partitions type possible_keys key  key_len ref  rows filtered Extra 
1 SIMPLE  activities NULL  range analyse   analyse 18  NULL 1  5.00  Using index condition; Using filesort 

在1.5秒的查询返回。我怎样才能优化这个?

感谢您的帮助。

+0

'ORDER BY'需要很长的时间...为什么你需要订购? – Eugene

+0

这会返回多少条记录? – e4c5

+0

@ e4c5它返回1k行 –

回答

2

此构造:end > 1471491882747 and timestamp_start < 1479267882747基本上不可能优化,主要是因为优化器确实知道是否可能存在重叠行。

INDEX(id_of_room, duration_s)可能使它运行得更快。如果使用,它将过滤id_of_roomduration_s,但更重要的是,它会避免文件。不知道我(和优化器)的值的分布无法预测这个指数是否会更好。对于某些价值可能会更好,对其他人更糟糕。

一个轻微的好处是改变BIGINTINT UNSIGNED或者甚至MEDIUMINT UNSIGNED酌情`。使用50M行时,缩小数据会减少I/O。

innodb_buffer_pool_size应该设置为RAM的70%左右。

潜在的重大帮助是避免SELECT *。只列出你需要的列。如果该列表足够短,则设计一个合成,覆盖,索引

一来加快查询最后的方法是用“懒惰的eval”:

SELECT a.* 
    FROM (SELECT activity_id 
     FROM activities 
     where id_of_room=3263 
      and timestamp_end>1471491882747 
      and timestamp_start<1479267882747 
      and duration_s>900 
     ) AS x 
    JOIN activities AS a USING(activity_id) 
    ORDER BY a.duration_s desc; 

如果使用覆盖索引派生表大量的行被过滤掉这将是有益的。在这种情况下,值得尝试排序索引列:

INDEX(id_of_room, duration_s, timestamp_start, timestamp_end, activity_id) 
+0

相当不错的答案+1,但看起来问题已经被放弃。 – e4c5

+0

@ e4c5 - 是什么让你觉得它被“抛弃”了? –

+0

OP没有回应两个评论和两个答案。 – e4c5