2013-10-24 70 views
1

我有以下的MySQL查詢,完美的作品,但有時運行速度慢得令人難以置信。優化我的查詢,使用IFNULL,JOIN和在哪裏在

SELECT s.ID AS `Student_ID` , IFNULL(COUNT(f.ID) , 0) AS `Flags` , IFNULL(COUNT(i.ID) , 0) AS `Interventions` 
    FROM `frog_shared`.`student` s 
    LEFT JOIN `frog_flags`.`flags` f ON s.ID = f.`Student_ID` 
    LEFT JOIN `frog_flags`.`interventions` i ON s.ID = i.`Student_ID` 
    WHERE s.ID 
    IN (132336) 
    GROUP BY s.ID 
    ORDER BY s.Surname ASC , s.Firstname DESC 

基本上,給學生ID列表,我希望我的系統返回的,他們已經收到Flags的數量和Interventions數量。

但是,當有30名學生的列表時,查詢需要花費將近一秒的時間。

查詢的結果時EXPLAIN版如下:

EXPLAIN outcome

我有student.idflags.Student_ID索引,所以我不認爲這就是問題所在。

如何優化我的查詢?

UPDATE:SHOW CREATE TABLES

CREATE TABLE `interventions` (
`ID` int(10) NOT NULL auto_increment, 
`Visible` int(1) NOT NULL, 
`Student_ID` int(6) NOT NULL COMMENT 'FK frog_shared.student', 
`Staff_ID` int(6) NOT NULL COMMENT 'FK frog_shared.staff', 
`Datetime` datetime NOT NULL, 
`Category_ID` int(3) NOT NULL COMMENT 'FK intervention_categories', 
`Generation_Type` varchar(1) NOT NULL COMMENT '[A]utomated or [M]anual', 
`Reason` text NOT NULL, 
`Status` varchar(1) NOT NULL COMMENT '[O]pen, In [P]rogress, [C]losed', 
PRIMARY KEY (`ID`) 
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1 

CREATE TABLE `flags` (
`ID` int(10) NOT NULL auto_increment, 
`Student_ID` int(6) NOT NULL COMMENT 'FK frog_shared.student', 
`Staff_ID` int(6) NOT NULL COMMENT 'FK frog_shared.staff', 
`Datetime` datetime NOT NULL, 
`Period_ID` int(2) NOT NULL COMMENT 'FK frog_shared.periods', 
`Location_ID` int(3) NOT NULL COMMENT 'FK frog_shared.locations', 
`Category_ID` int(2) NOT NULL COMMENT 'FK flag_categories', 
`Alert_ID` int(11) default NULL COMMENT 'FK frog_alerts.alerts', 
`Action_Taken_Category_ID` int(1) default NULL COMMENT 'FK frog_flags.categories FA', 
`Action_Taken_Status` varchar(1) default NULL COMMENT '[P]ending or [C]omplete', 
`Details` text NOT NULL, 
PRIMARY KEY (`ID`), 
KEY `Student_ID` (`Student_ID`), 
KEY `Staff_ID` (`Staff_ID`), 
KEY `Datetime` (`Datetime`) 
) ENGINE=InnoDB AUTO_INCREMENT=3669 DEFAULT CHARSET=latin1 

CREATE TABLE `student` (
`id` varchar(20) default NULL, 
`UPN` varchar(25) NOT NULL, 
`Firstname` varchar(50) NOT NULL, 
`Surname` varchar(50) NOT NULL, 
`Year_Group` int(2) NOT NULL, 
`Tutor_Group` varchar(15) NOT NULL, 
`SEN_Status` varchar(1) default NULL, 
`Flags` varchar(10) default NULL, 
PRIMARY KEY (`UPN`), 
KEY `id` (`id`), 
KEY `Year_Group` (`Year_Group`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 
+0

對不起,我不明白這個問題? – dunc

+0

你到目前爲止嘗試過哪些方法來優化它,它是靜態IN(132336)?或來自變量。 – developerCK

+0

我還沒有真正嘗試過任何東西 - 我不知道從哪裏開始。'IN'命令由PHP動態填充,因此它可以是'IN(13141)'或它可以是'IN(121,131,141,155,142,144,...)等。 – dunc

回答

3

我建議擺脫GROUP BY和JOINs,因爲他們似乎沒有必要獲得你想要的結果。

SELECT 
s.ID AS `Student_ID` , 
(
    SELECT COUNT(*) FROM `frog_flags`.`flags` f 
    WHERE s.ID = f.`Student_ID` 
) AS `Flags` , 
(
    SELECT COUNT(*) FROM `frog_flags`.`interventions` i 
    WHERE s.ID = i.`Student_ID` 
) AS `Interventions` 
FROM `frog_shared`.`student` s 
WHERE s.ID 
IN (132336) 
ORDER BY s.Surname ASC , s.Firstname DESC 

確保指數的interventions.Student_ID,你應該是不錯的,當你在該表中獲取一些數據去。

讓我知道這個重構是否有問題。

+0

感謝威廉,看起來好像更快。你能否簡要解釋爲什麼我不需要'GROUP BY'和'JOINS'以及爲什麼這些子查詢更快? – dunc

+0

很好的答案。通過「select子查詢」進行計數要比「GROUP BY」結構更簡單和更清晰,並且可以擴展 - 檢索多個單獨的計數或函數 - 要好得多。 –

+0

至於爲什麼更快......'COUNT(*)'比'COUNT(column)'快得多,並且從外連接計數可能爲null的行可能會更慢。查詢仍然暗含某種連接,因爲子查詢是_correlated_ ..擺脫「GROUP BY」並簡化「COUNT」子句可能是主要區別。 –

1

在MySQL中,對於profilling查詢步驟是

首先執行

set profiling=1; 

然後執行要分析

<your query> 
查詢

然後執行

show PROFILES; 

它會給結果像

+----------+------------+-----------------------------+ 
| Query_ID | Duration | Query      | 
+----------+------------+-----------------------------+ 
|  1 | 0.00057500 | Your query 
+----------+------------+-----------------------------+ 

然後exeucte

show Profile for query 1; 

reuslt像

+----------------------+----------+ 
| Status    | Duration | 
+----------------------+----------+ 
| starting    | 0.000105 | 
| checking permissions | 0.000014 | 
| Opening tables  | 0.000026 | 
| System lock   | 0.000006 | 
| Table lock   | 0.000051 | 
| init     | 0.000044 | 
| optimizing   | 0.000009 | 
| statistics   | 0.000019 | 
| preparing   | 0.000014 | 
| executing   | 0.000213 | 
| end     | 0.000031 | 
| query end   | 0.000004 | 
| freeing items  | 0.000030 | 
| logging slow query | 0.000004 | 
| cleaning up   | 0.000005 | 

特結果是一個花費更多時間執行的檢查。 這裏是一個很好的優化mysql查詢的文檔:http://www.percona.com/files/presentations/percona-live/dc-2012/PLDC2012-mysql-query-optimization.pdf