2016-11-16 20 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