优化我使用IFNULL,JOIN和WHERE IN的查询

时间:2013-10-24 12:12:11

标签: mysql

我有以下MySQL查询,它运行得很好,但有时运行得非常慢。

    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上有索引,所以我认为这不是问题所在。

我还能如何优化查询?

更新:SHOW CREATE表格

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

2 个答案:

答案 0 :(得分:3)

我建议摆脱GROUP BY和JOIN,因为它们似乎没有必要获得你想要的结果。

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上有一个索引,当你在该表中获得一些数据时,你应该好好去。

如果重构有任何问题,请告诉我。

答案 1 :(得分:1)

在mysql中,用于查询查询的步骤是

首先执行

set profiling=1;

然后执行您要分析的查询

<your query>

然后执行

show PROFILES;

它会给出像

这样的结果
+----------+------------+-----------------------------+
| Query_ID | Duration   | Query                       |
+----------+------------+-----------------------------+
|        1 | 0.00057500 | Your query
+----------+------------+-----------------------------+

然后exeucte

show Profile for query 1;

重新审视

+----------------------+----------+
| 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