2015-09-23 147 views
1

我有一個非常緩慢的MySQL查詢如下:很慢的簡單的MySQL查詢

SELECT function, CONVERT_TZ(`time`, '+01:00','+01:00') 
FROM `function_logger` 
WHERE unit_id=3067785 
    and part_id=3 and channel=0 
    and `time` > NOW()-INTERVAL 1 DAY 
order by time; 

爲下表結構

CREATE TABLE IF NOT EXISTS `function_logger` (
    `id` int(11) NOT NULL, 
    `unit_id` int(11) NOT NULL, 
    `part_id` tinyint(4) NOT NULL DEFAULT '0', 
    `channel` tinyint(4) NOT NULL DEFAULT '0', 
    `function` tinyint(11) NOT NULL, 
    `time` datetime NOT NULL 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

ALTER TABLE `function_logger` 
    ADD PRIMARY KEY (`id`), 
    ADD KEY `unit_id` (`unit_id`); 

表中包含約80萬條記錄,但周圍一分鐘花費跑。一旦緩存就沒問題。

UNIT_ID包含約3000張不同的隨機數,PART_ID高達10通道高達3

反正是有加快這?

分區幫助嗎?

+2

添加覆蓋索引'改變表function_logger添加索引search_idx(UNIT_ID,PART_ID,通道,時間)' –

+2

什麼是從一個時區轉換'time'到同一時區的地步? – eggyal

+0

@AbhikChakraborty:這不是一個覆蓋索引... – eggyal

回答

2

假設統一分配unit_id,那麼在80m記錄中選擇特定的一個(3000)會留下超過25k條記錄來檢查。

由於您沒有進一步的索引來輔助,因此MySQL目前必須檢索並檢查這25k條記錄中的每條記錄,以確定它們是否與剩餘的過濾條件匹配。

添加一個composite索引(即在多列上定義的索引)可以幫助您,因此MySQL可以進一步減少它需要檢查的記錄。然而,如此低的基數,part_idchannel可能沒有多大幫助。目前尚不清楚,從time可能存在什麼樣的基數,但是這可能是一個很好的起點:

CREATE INDEX unit_time ON function_logger (unit_id, time) 

您可以添加其它過濾列太(雖然提防time應最後到來,因爲你正在尋找一個範圍) - 但是,索引中的列越多,寫入表的速度越慢(索引文件和內存佔用量將越大)。

最快的讀取性能會從covering指數獲得:

CREATE INDEX covering ON function_logger (
    unit_id, part_id, channel, time, function 
) 
+0

非常感謝。 有了覆蓋索引,它現在幾乎立即選擇記錄。 –

0

試圖在/ tesing不同指標執行解釋,並比較結果。 USE INDEX將幫助您測試在select語句中添加提示的不同索引(請記住不要使用qc)。

set profiling = on; 

select * from function_logger; 
show profiles; 
show profile for query N;