2015-09-04 75 views
2

我爲我們的用戶PC創建了一個簡單的統計工具。它每5分鐘記錄我們所有電腦的狀態。而一個前端給我一個用法圖: enter image description here優化SQL子查詢統計

現在隨着數據越來越多,SQL查詢越來越慢,我正在尋找一種方法來優化它。

這是結構。正如你所看到的,表「使用」載約6萬條記錄,並使用MySQL的InnoDB:

CREATE TABLE IF NOT EXISTS `usage` (
`id` int(11) unsigned NOT NULL, 
    `host_id` int(10) unsigned NOT NULL, 
    `time` int(10) unsigned NOT NULL, 
    `state` enum('LinuxTU','LinuxExt','View','Browser','Idle','Offline') CHARACTER SET latin1 NOT NULL DEFAULT 'Offline' 
) ENGINE=InnoDB AUTO_INCREMENT=5963366 DEFAULT CHARSET=utf8; 

ALTER TABLE `usage` 
ADD PRIMARY KEY (`id`), ADD KEY `host_id` (`host_id`), ADD KEY `time` (`time`); 

ALTER TABLE `usage` 
MODIFY `id` int(11) unsigned NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=5963366; 

下面的查詢需要大約7秒執行。這是將數據提供給屏幕截圖的查詢。

/* create pivot table */ 
SELECT `time`, 
    SUM(IF(state='LinuxTU', statecount, 0)) AS LinuxTU, 
    SUM(IF(state='LinuxExt', statecount, 0)) AS LinuxExt, 
    SUM(IF(state='View', statecount, 0)) AS View, 
    SUM(IF(state='Browser', statecount, 0)) AS Browser 
FROM (
    /* get data from last 24h grouped by state */ 
    SELECT `time`, `state`, COUNT(`state`) statecount 
    FROM `usage` u 
    /* group by time to get every 5 minutes 
     group by state to get the state counter */ 
    GROUP BY `time`, `state` 
    HAVING `time` > 1441271078 AND `time` < 1441357478 
) AS s 
GROUP BY `time` 
ORDER BY `time` ASC 

我不知道如何優化它。有什麼我錯過了嗎?或者我需要重新組織結構?任何提示?

回答

0

我覺得你的問題是因爲子查詢的指標都沒有了對最後

GROUP BY `time` 
ORDER BY `time` ASC 

。所以,你應該找到一種方法來消除這種情況。

您是否也可以選擇使用編程語言進行一些處理?只需在內部選擇+外部選擇無變量的變量,並添加順序,然後在編程語言中進行處理。

或者你必須在查詢中寫這個嗎?

+0

我可以通過改變從一個ENUM字段的表到多個國家領域消除支點查詢(如LinuxTU = 0,LinuxExt = 1)。但是我認爲多個領域使得它變得僵化和可能更爲緊張(例如:LinuxTU = 1和LinuxExt = 1)。實際上前端使用這些數據。所以每個查詢都會輸出所需的數據。 – Michael

0

我發現了瓶頸。問題是內部查詢。 HAVING似乎比WHERE慢得多。於是,我嘗試了一些不同的查詢,現在我得到這樣的結果:

需要7秒時:

SELECT `time`, `state`, COUNT(`state`) statecount 
FROM `usage` u 
GROUP BY `time`, `state` 
HAVING `time` > 1441271078 AND `time` < 1441357478 

用0.1秒時:

SELECT `time`, `state`, COUNT(`state`) `statecount` 
FROM `usage` u 
WHERE `time` > 1441271078 AND `time` < 1441357478 
GROUP BY `time`, `state` 

,給我相同的結果。前端現在快得多。

2

除了移動time比較成where條款,你可以擺脫完全的子查詢:

/* create pivot table */ 
SELECT `time`, 
     SUM(state = 'LinuxTU') AS LinuxTU, 
     SUM(state = 'LinuxExt') AS LinuxExt, 
     SUM(state = 'View') AS View, 
     SUM(state = 'Browser') AS Browser 
FROM usage u 
WHERE `time` > 1441271078 AND `time` < 1441357478 
GROUP BY `time` 
ORDER BY `time` ASC;