我有以下小提琴http://sqlfiddle.com/#!2/21cee/2
这是数据库表的架构:
平均值:
id
subject_id
student_id
value
semester_id
classes_students :
id
class_academic_year_id
student_id
classes_academic_years :
id
class_id
name
academic_year_id
grade
classes_subjects :
id
class_academic_year_id
subject_id
class_masters :
id
class_academic_year_id
professor_id
教授:
id
school_id
first_name
last_name
professors_subjects :
id
professor_id
subject_id
professors_classes_subjects :
id
professor_id
class_academic_year_id
subject_id
受试者:
id
name
school_id
default
学期:
id
name
academic_year_id
start_date
end_date
生:
id
last_name
first_name
我收到了以下问题:
SELECT `averages`.*
FROM `averages`
INNER JOIN `classes_students` ON classes_students.student_id = averages.student_id
INNER JOIN `classes_academic_years` ON classes_academic_years.id = classes_students.class_academic_year_id
INNER JOIN `classes_subjects` ON classes_subjects.class_academic_year_id = classes_academic_years.id
INNER JOIN `subjects` ON subjects.id = classes_subjects.subject_id
INNER JOIN `professors_classes_subjects` ON professors_classes_subjects.class_academic_year_id = classes_subjects.class_academic_year_id
INNER JOIN `professors_subjects` ON professors_subjects.professor_id = professors_classes_subjects.professor_id
INNER JOIN `professors` ON professors.id = professors_subjects.professor_id
INNER JOIN `semesters` ON semesters.academic_year_id = classes_academic_years.academic_year_id
INNER JOIN `students` ON students.id = classes_students.student_id
WHERE (classes_academic_years.academic_year_id = 3)
AND (subjects.id = 72)
AND (professors.id = 198)
AND (professors_classes_subjects.subject_id = subjects.id)
AND (professors_subjects.subject_id = subjects.id)
AND (averages.subject_id = subjects.id)
AND (averages.semester_id = semesters.id)
ORDER BY `averages`.`student_id` asc, `averages`.`semester_id` asc;
和
SELECT `averages`.*
FROM `averages`
INNER JOIN `classes_students` ON classes_students.student_id = averages.student_id
INNER JOIN `classes_academic_years` ON classes_academic_years.id = classes_students.class_academic_year_id
INNER JOIN `classes_subjects` ON classes_subjects.class_academic_year_id = classes_academic_years.id
INNER JOIN `subjects` ON subjects.id = classes_subjects.subject_id
INNER JOIN `class_masters` ON class_masters.class_academic_year_id = classes_academic_years.id
INNER JOIN `semesters` ON semesters.academic_year_id = classes_academic_years.academic_year_id
INNER JOIN `students` ON students.id = classes_students.student_id
WHERE (classes_academic_years.academic_year_id = 3)
AND (subjects.id = 72)
AND (class_masters.professor_id = 198)
AND (averages.subject_id = subjects.id)
AND (averages.semester_id = semesters.id)
ORDER BY `averages`.`student_id` asc, `averages`.`semester_id` asc;
第一个查询获取教授所分配的所有课程的某个教授(subject_id = 72
)的某个科目(professor_id = 198
)的平均值。
由于professor_id = 198
没有为任何类分配给subject_id = 72
,因此结果将为空。
第二个查询获取某个教授(subject_id = 72
)的某个主题(professor_id = 198
)的平均值,仅检查给定教授是class_master的那些类,而不管哪个教授是分配给该课程的该科目。
两个查询都运行正常。我需要结合这两个查询,这是我的尝试:
SELECT DISTINCT `averages`.* FROM `averages`
INNER JOIN `classes_students` ON classes_students.student_id = averages.student_id
INNER JOIN `classes_academic_years` ON classes_academic_years.id = classes_students.class_academic_year_id
INNER JOIN `classes_subjects` ON classes_subjects.class_academic_year_id = classes_academic_years.id
INNER JOIN `subjects` ON subjects.id = classes_subjects.subject_id
LEFT JOIN `professors_classes_subjects` ON professors_classes_subjects.class_academic_year_id = classes_subjects.class_academic_year_id
LEFT JOIN `professors_subjects` ON professors_subjects.professor_id = professors_classes_subjects.professor_id
LEFT JOIN `professors` ON professors.id = professors_subjects.professor_id
LEFT JOIN `class_masters` ON class_masters.class_academic_year_id = classes_academic_years.id
INNER JOIN `semesters` ON semesters.academic_year_id = classes_academic_years.academic_year_id
INNER JOIN `students` ON students.id = classes_students.student_id
WHERE (classes_academic_years.academic_year_id = 3)
AND (subjects.id = 72)
AND ((professors.id = 198
AND professors_classes_subjects.subject_id = subjects.id
AND professors_subjects.subject_id = subjects.id)
OR (class_masters.id is not null AND class_masters.professor_id = 198))
AND (averages.subject_id = subjects.id)
AND (averages.semester_id = semesters.id)
ORDER BY `averages`.`student_id` asc, `averages`.`semester_id` asc;
虽然它确实工作正常,但它也非常慢(例如,它在我的本地计算机上运行大约需要5秒钟。)
有没有办法改进第三个查询?
LE:这里是EXPLAIN:
+----+-------------+-----------------------------+--------+---------------------------------------------------------------------+-----------------------------------+---------+-----------------------------------------------+------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------------------+--------+---------------------------------------------------------------------+-----------------------------------+---------+-----------------------------------------------+------+----------------------------------------------------+
| 1 | SIMPLE | subjects | const | PRIMARY | PRIMARY | 8 | const | 1 | Using index; Using temporary; Using filesort |
| 1 | SIMPLE | averages | ref | subject_id_student_id_semester_id | subject_id_student_id_semester_id | 8 | const | 1087 | (NULL) |
| 1 | SIMPLE | students | eq_ref | PRIMARY | PRIMARY | 8 | averages.student_id | 1 | Using index |
| 1 | SIMPLE | classes_students | ref | student_id,class_academic_year_id_student_id | student_id | 8 | averages.student_id | 2 | (NULL) |
| 1 | SIMPLE | semesters | eq_ref | PRIMARY,academic_year_id | PRIMARY | 4 | averages.semester_id | 1 | (NULL) |
| 1 | SIMPLE | classes_subjects | ref | subject_id,class_academic_year_id,class_academic_year_id_subject_id | class_academic_year_id_subject_id | 16 | classes_students.class_academic_year_id,const | 1 | Using index |
| 1 | SIMPLE | classes_academic_years | eq_ref | PRIMARY,id_class_id_academic_year_id,id_academic_year_id | PRIMARY | 8 | classes_students.class_academic_year_id | 1 | Using where |
| 1 | SIMPLE | professors_classes_subjects | ALL | (NULL) | (NULL) | (NULL) | (NULL) | 822 | Using where; Using join buffer (Block Nested Loop) |
| 1 | SIMPLE | professors_subjects | ALL | (NULL) | (NULL) | (NULL) | (NULL) | 304 | Using where; Using join buffer (Block Nested Loop) |
| 1 | SIMPLE | professors | eq_ref | PRIMARY | PRIMARY | 8 | professors_subjects.professor_id | 1 | Using index |
| 1 | SIMPLE | class_masters | ALL | (NULL) | (NULL) | (NULL) | (NULL) | 97 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-----------------------------+--------+---------------------------------------------------------------------+-----------------------------------+---------+-----------------------------------------------+------+----------------------------------------------------+
LE:我已经设法通过改进两个LEFT JOIN的ON条件来解决它:
SELECT averages.* FROM `averages`
INNER JOIN `classes_students` ON classes_students.student_id = averages.student_id
INNER JOIN `classes_academic_years` ON classes_academic_years.id = classes_students.class_academic_year_id
INNER JOIN `classes_subjects` ON classes_subjects.class_academic_year_id = classes_academic_years.id
INNER JOIN `subjects` ON subjects.id = classes_subjects.subject_id
LEFT JOIN `professors_classes_subjects` ON professors_classes_subjects.class_academic_year_id = classes_subjects.class_academic_year_id AND professors_classes_subjects.subject_id = subjects.id
LEFT JOIN `professors_subjects` ON professors_subjects.professor_id = professors_classes_subjects.professor_id AND professors_subjects.subject_id = subjects.id
LEFT JOIN `professors` ON professors.id = professors_subjects.professor_id
LEFT JOIN `class_masters` ON class_masters.class_academic_year_id = classes_academic_years.id
INNER JOIN `semesters` ON semesters.academic_year_id = classes_academic_years.academic_year_id
INNER JOIN `students` ON students.id = classes_students.student_id
WHERE (classes_academic_years.academic_year_id = 3)
AND (subjects.id = 72)
AND ((professors.id = 198)
OR (class_masters.id is not null AND class_masters.professor_id = 198))
AND (averages.subject_id = subjects.id)
AND (averages.semester_id = semesters.id)
ORDER BY `averages`.`student_id` asc, `averages`.`semester_id` asc;
我添加了两个条件(标记为粗体),因此无需使用DISTINCT运算符:
LEFT JOIN professors_classes_subjects ON professors_classes_subjects.class_academic_year_id = classes_subjects.class_academic_year_id
AND professors_classes_subjects.subject_id = subjects.id
LEFT JOIN professors_subjects ON professors_subjects.professor_id = professors_classes_subjects.professor_id
AND professors_subjects.subject_id = subjects.id
答案 0 :(得分:0)
我设法通过改进两个LEFT JOIN的ON条件来解决它:
SELECT averages.* FROM `averages`
INNER JOIN `classes_students` ON classes_students.student_id = averages.student_id
INNER JOIN `classes_academic_years` ON classes_academic_years.id = classes_students.class_academic_year_id
INNER JOIN `classes_subjects` ON classes_subjects.class_academic_year_id = classes_academic_years.id
INNER JOIN `subjects` ON subjects.id = classes_subjects.subject_id
LEFT JOIN `professors_classes_subjects` ON professors_classes_subjects.class_academic_year_id = classes_subjects.class_academic_year_id AND professors_classes_subjects.subject_id = subjects.id
LEFT JOIN `professors_subjects` ON professors_subjects.professor_id = professors_classes_subjects.professor_id AND professors_subjects.subject_id = subjects.id
LEFT JOIN `professors` ON professors.id = professors_subjects.professor_id
LEFT JOIN `class_masters` ON class_masters.class_academic_year_id = classes_academic_years.id
INNER JOIN `semesters` ON semesters.academic_year_id = classes_academic_years.academic_year_id
INNER JOIN `students` ON students.id = classes_students.student_id
WHERE (classes_academic_years.academic_year_id = 3)
AND (subjects.id = 72)
AND ((professors.id = 198)
OR (class_masters.id is not null AND class_masters.professor_id = 198))
AND (averages.subject_id = subjects.id)
AND (averages.semester_id = semesters.id)
ORDER BY `averages`.`student_id` asc, `averages`.`semester_id` asc;
我添加了两个条件(标记为粗体),因此无需使用DISTINCT运算符:
LEFT JOIN professors_classes_subjects
ON professors_classes_subjects.class_academic_year_id = classes_subjects.class_academic_year_id
AND professors_classes_subjects.subject_id = subjects.id
LEFT JOIN professors_subjects
ON professors_subjects.professor_id = professors_classes_subjects.professor_id
AND professors_subjects.subject_id = subjects.id