我如何针对 sql 优化此查询以计算响应

How can i optimize this query for sql for counting response

我有 table 个问题的回复,当我尝试通过查询计算问题的回复数量以创建图表时,加载需要 65 秒

请指导我如何优化此查询

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

尝试条件聚合:

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

或者使用 SUM 而不是 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

您可以在任何聚合函数中使用 IF() 函数。诀窍是 COUNT() 不仅计算空值,所以将 NULL 放入 "else" 部分。喜欢这里:

SELECT 
  COUNT(IF(response=1,1,NULL)) AS one_star,
  COUNT(IF(response=2,1,NULL)) AS two_star,
  COUNT(IF(response=3,1,NULL)) AS three_star,
  COUNT(IF(response=4,1,NULL)) AS four_star,
  COUNT(IF(response=5,1,NULL)) 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" 操作来做同样的事情:

  COUNT(response=1 OR NULL) AS one_star,

对我来说,这是最短、最容易理解的选项。

请注意,对于任何查询优化问题,您应该为查询中涉及的每个 table 提供 SHOW CREATE TABLE tablename 语句。

也就是说,如果以下索引不存在,请将它们添加到您的 table 中:

survey: (user_id,status)
questions: (survey_id)
visitor_responses: (question_id,response)

以上索引假设idsurveyquestions上table分别是每个table的主键。

报告如何改进性能,并包括每个 table 的最新 SHOW CREATE TABLE tablename 语句,这样我们可以帮助确保您没有任何冗余索引现在。

如果性能不低于 1 秒,或任何其他您想超越的阈值,还包括当前的 EXPLAIN 计划。