我有以下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
编辑时的查询结果如下:
我在student.id
和flags.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
答案 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