mysqlquery-optimizationsql-optimization

How can i optimize this query for sql for counting response


I have a table of response from the question and when i try to count the number of response over the question by query for creating a graph it took 65seconds to load

so can please guide me someone how can we optimize this query

SELECT
vr.question_id,
(SELECT COUNT(response) FROM visitors_response  WHERE question_id = vr.question_id AND response = 5 ) AS one_star,
(SELECT COUNT(response) FROM visitors_response  WHERE question_id = vr.question_id AND response = 4 ) AS two_star,
(SELECT COUNT(response) FROM visitors_response  WHERE question_id = vr.question_id AND response = 3 ) AS three_star,
(SELECT COUNT(response) FROM visitors_response  WHERE question_id = vr.question_id AND response = 2 ) AS four_star,
(SELECT COUNT(response) FROM visitors_response  WHERE question_id = vr.question_id AND response = 1 ) AS five_star,
(SELECT AVG(response)   FROM visitors_response  WHERE question_id = vr.question_id ) AS average 
FROM visitors_response vr
JOIN questions q ON q.id = vr.question_id 
JOIN survey s ON s.id = q.survey_id
WHERE s.user_id = 101 AND s.status = 'active' 
GROUP BY vr.question_id

Solution

  • Try with conditional aggregation:

    SELECT
    vr.question_id,
    COUNT(CASE WHEN response = 5 THEN response END) AS one_star,
    COUNT(CASE WHEN response = 4 THEN response END) AS two_star,
    COUNT(CASE WHEN response = 3 THEN response END) AS three_star,
    COUNT(CASE WHEN response = 2 THEN response END) AS four_star,
    COUNT(CASE WHEN response = 1 THEN response END) AS five_star,
    AVG(response) AS average 
    FROM visitors_response vr
    JOIN questions q ON q.id = vr.question_id 
    JOIN survey s ON s.id = q.survey_id
    WHERE s.user_id = 101 AND s.status = 'active' 
    GROUP BY vr.question_id
    

    Or by using SUM instead of COUNT:

    SELECT
    vr.question_id,
    SUM(response = 5) AS one_star,
    SUM(response = 4) AS two_star,
    SUM(response = 3) AS three_star,
    SUM(response = 2) AS four_star,
    SUM(response = 1) AS five_star,
    AVG(response) AS average 
    FROM visitors_response vr
    JOIN questions q ON q.id = vr.question_id 
    JOIN survey s ON s.id = q.survey_id
    WHERE s.user_id = 101 AND s.status = 'active' 
    GROUP BY vr.question_id