简体   繁体   中英

subselect alternatives

Take a look at this query, please:

SELECT
    (SELECT COUNT(id) FROM result WHERE `mterm1` > r.mterm1 AND lesson_id = r.lesson_id) + 1 AS `pos_mt1_school`,
    (SELECT COUNT(id) FROM result WHERE `mterm1` > r.mterm1 AND lesson_id = r.lesson_id AND class_id = r.class_id) + 1 AS `pos_mt1_class`,

    (SELECT COUNT(id) FROM result WHERE `term1` > r.term1 AND lesson_id = r.lesson_id) + 1 AS `pos_t1_school`,
    (SELECT COUNT(id) FROM result WHERE `term1` > r.term1 AND lesson_id = r.lesson_id AND class_id = r.class_id) + 1 AS `pos_t1_class`,

    (SELECT COUNT(id) FROM result WHERE `mterm2` > r.mterm2 AND lesson_id = r.lesson_id) + 1 AS `pos_mt2_school`,
    (SELECT COUNT(id) FROM result WHERE `mterm2` > r.mterm2 AND lesson_id = r.lesson_id AND class_id = r.class_id) + 1 AS `pos_mt2_class`,

    (SELECT COUNT(id) FROM result WHERE `term2` > r.term2 AND lesson_id = r.lesson_id) + 1 AS `pos_t2_school`,
    (SELECT COUNT(id) FROM result WHERE `term2` > r.term2 AND lesson_id = r.lesson_id AND class_id = r.class_id) + 1 AS `pos_t2_class`,

    r.*, student.* FROM result r

LEFT JOIN lessons lesson ON r.lesson_id = lesson.id
LEFT JOIN students student ON r.student_id = student.id
LEFT JOIN classes class ON student.class_id = class.id

WHERE student.id = 217 ORDER BY lesson.id ASC

I want to show student exam scores. So, first select his results (exam scores) from table result , then join lessons to show lesson name, and finally calculate student position in each lesson in his class and school. (based on his exam score)

That query works fine, but it takes about 2 seconds to be executed. (performance problem)

Is there any optimization for that query? (and an alternative for its subselect queries)

You are doing cumulative counts in the subselects.

I cannot readily think of another way of doing this in MySQL in a single query. If the ">" where an "=", this could be turned into a join. But that is not possible in this case.

You can turn this into an explicit cross join with an aggregation, using a query such as this:

SELECT sum(case when r2.mterm1  > r.mterm1 then 1 else 0 end)+1 as `pos_mt1_school`,
       sum(case when r2.mterm1 > r.mterm1 and r2.class_id = r.class_id) + 1 then 1 else 0 end) AS `pos_mt1_class`,
       . . .
    r.*, student.*
FROM result r LEFT JOIN
     lessons lesson
     ON r.lesson_id = lesson.id LEFT JOIN
     students student
     ON r.student_id = student.id LEFT JOIN
     classes class
     ON student.class_id = class.id join
     result r2
     on r.lesson_id = r2.lesson_id
WHERE student.id = 217
group by r.result_id
ORDER BY lesson.id ASC

I'm not sure this will be faster than the original version. The original version, by the way, would be sped up by putting on two indexes: result(lesson_id, term2) and result(less_id, class_id, term2).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM