MySQL 查看聚合查询的性能问题
MySQL View performance issue with aggregate query
我正在使用 mysql 版本 5.6.47。
我有以下 table 学生成绩:
CREATE TABLE `studentmarks` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`StudentID` int(11) NOT NULL,
`subjectName` varchar(255) DEFAULT NULL,
`MARKS` int(11) NOT NULL,
PRIMARY KEY (`ID`),
KEY `idx_studentmarks_StudentID` (`StudentID`)
);
并在 table 上创建了一个视图:
CREATE OR REPLACE VIEW `vw_student_marks` AS
SELECT
`s1`.`StudentID` AS `StudentID`,
`s1`.`subjectName` AS `subjectName`,
`s1`.`MARKS` AS `marks`,
(SELECT
SUM(`s2`.`MARKS`)
FROM
`studentmarks` `s2`
WHERE
(`s2`.`StudentID` = `s1`.`StudentID`)) AS `totalMarks`
FROM
`studentmarks` `s1`;
当测试大约 20K 行时,运行 SELECT query
与 SELECT * FROM VIEW
的性能存在明显差异。 select 查询显示优化的执行计划,只有 1 次完整 table 扫描,而视图有 2 次完整 table 扫描。
查询统计数据(由 MySQL Workbench 测量):
SELECT 查询
Timing: 0:00:0.07677120 (as measured by the server)
Rows Examined: 108285
SELECT 来自查看查询:
Timing: 0:00:1.6082441 (as measured by the server)
Rows Examined: 2985730
这种性能差异背后的原因是什么?
查询执行计划:https://i.stack.imgur.com/noOxI.jpg
更新:我用 MySQL 版本 8.0.19 进行了测试,出现了同样的问题
在这种情况下,MySQL 必须对视图使用 TEMPTABLE 算法(聚合函数)。这可能是造成差异的原因。
详情请参考https://dev.mysql.com/doc/refman/5.6/en/view-algorithms.html。
If the MERGE algorithm cannot be used, a temporary table must be used
instead. MERGE cannot be used if the view contains any of the
following constructs:
Aggregate functions (SUM(), MIN(), MAX(), COUNT(), and so forth)
DISTINCT
GROUP BY
HAVING
LIMIT
UNION or UNION ALL
Subquery in the select list
Assignment to user variables
Refers only to literal values (in this case, there is no underlying
table)
FWIW,我会使用不相关的子查询来编写此代码(但我承认它不一定会提高性能)- 并放弃完全使用视图的想法...
SELECT s1.StudentID
, s1.subjectName
, s1.MARKS
, s2.totalmarks
FROM studentmarks s1
JOIN
( SELECT studentid
, SUM(s2.MARKS) totalmarks
FROM studentmarks
GROUP
BY studentid
) s2
ON s2.studentid = s1.studentid;
我正在使用 mysql 版本 5.6.47。 我有以下 table 学生成绩:
CREATE TABLE `studentmarks` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`StudentID` int(11) NOT NULL,
`subjectName` varchar(255) DEFAULT NULL,
`MARKS` int(11) NOT NULL,
PRIMARY KEY (`ID`),
KEY `idx_studentmarks_StudentID` (`StudentID`)
);
并在 table 上创建了一个视图:
CREATE OR REPLACE VIEW `vw_student_marks` AS
SELECT
`s1`.`StudentID` AS `StudentID`,
`s1`.`subjectName` AS `subjectName`,
`s1`.`MARKS` AS `marks`,
(SELECT
SUM(`s2`.`MARKS`)
FROM
`studentmarks` `s2`
WHERE
(`s2`.`StudentID` = `s1`.`StudentID`)) AS `totalMarks`
FROM
`studentmarks` `s1`;
当测试大约 20K 行时,运行 SELECT query
与 SELECT * FROM VIEW
的性能存在明显差异。 select 查询显示优化的执行计划,只有 1 次完整 table 扫描,而视图有 2 次完整 table 扫描。
查询统计数据(由 MySQL Workbench 测量):
SELECT 查询
Timing: 0:00:0.07677120 (as measured by the server)
Rows Examined: 108285
SELECT 来自查看查询:
Timing: 0:00:1.6082441 (as measured by the server)
Rows Examined: 2985730
这种性能差异背后的原因是什么?
查询执行计划:https://i.stack.imgur.com/noOxI.jpg
更新:我用 MySQL 版本 8.0.19 进行了测试,出现了同样的问题
MySQL 必须对视图使用 TEMPTABLE 算法(聚合函数)。这可能是造成差异的原因。
详情请参考https://dev.mysql.com/doc/refman/5.6/en/view-algorithms.html。
If the MERGE algorithm cannot be used, a temporary table must be used instead. MERGE cannot be used if the view contains any of the following constructs:
Aggregate functions (SUM(), MIN(), MAX(), COUNT(), and so forth)
DISTINCT
GROUP BY
HAVING
LIMIT
UNION or UNION ALL
Subquery in the select list
Assignment to user variables
Refers only to literal values (in this case, there is no underlying table)
FWIW,我会使用不相关的子查询来编写此代码(但我承认它不一定会提高性能)- 并放弃完全使用视图的想法...
SELECT s1.StudentID
, s1.subjectName
, s1.MARKS
, s2.totalmarks
FROM studentmarks s1
JOIN
( SELECT studentid
, SUM(s2.MARKS) totalmarks
FROM studentmarks
GROUP
BY studentid
) s2
ON s2.studentid = s1.studentid;