建议优化mysql查询

时间:2014-10-28 09:13:41

标签: mysql

说明: Complaint_status包含多行用于特定投诉,试图获得用户明智的关闭投诉(状态= 2且值IN(1,2))

痛点:

YEAR(cs.created_at)=year(curdate()) 
AND MONTH(cs.created_at)=month(curdate())

在本地服用近5分钟,在服务器上服用1.5分钟

SELECT u3.name,COUNT(c3.id) as closed_tickets
FROM complaint c3,complaint_status cs,assignment a3,user u3
WHERE
c3.id=cs.complaint_id
AND a3.complaint_id=c3.id
AND u3.id=a3.assigned_to
AND u3.user_type=14
AND a3.expiry IS NULL
AND cs.id IN(SELECT MAX(id) FROM complaint_status WHERE complaint_id=c3.id AND status=2 AND value IN(1,2))
AND YEAR(cs.created_at)=year(curdate()) 
AND MONTH(cs.created_at)=month(curdate())
GROUP BY u3.id 
ORDER BY COUNT(c3.id) DESC

3 个答案:

答案 0 :(得分:1)

WHERE子句中应用此谓词的问题:

YEAR(cs.created_at)=year(curdate()) 
AND MONTH(cs.created_at)=month(curdate())

MySql是否需要为所有记录(或至少剩余的记录)评估这些函数。这里的浪费是这些有效的常数,取决于当前的日期。假设created_at上有一个索引,您可以通过将日期与本月的第一天进行比较,而不是将下个月的第一天进行比较,来提高hitting the index的可能性(并假设created_at是DATE):

...

   cs.created_at >= DATE_SUB(CURRENT_DATE, INTERVAL DAYOFMONTH(CURRENT_DATE)-1 DAY),
   AND cs.created_at < DATE_ADD(LAST_DAY(CURRENT_DATE), INTERVAL + 1 DAY)

请注意,结束日期不包括上限(因为这可能包括下个月第一秒的数据)

答案 1 :(得分:1)

首先,您应该修复join状态。

其次,而不是:

YEAR(cs.created_at) = year(curdate()) AND MONTH(cs.created_at) = month(curdate())

使用:

cs.created_at >= curdate() and cs_created_at < date_sub(date_sub, curdate(), interval day(curdate()) - 1, interval 1 month)

这将允许该字段使用具有created_at

的任何索引

这似乎是您的具体问题。

如果你真的想要优化查询,我建议用问另一个问题:

  • 使用显式连接重写的查询
  • 表格布局(或至少现有索引)
  • 查询的解释计划。

答案 2 :(得分:1)

尝试:

SELECT u3.name,
       COUNT(c3.id) AS closed_tickets
FROM complaint c3
JOIN complaint_status cs
  ON c3.id=cs.complaint_id
JOIN ASSIGNMENT a3
  ON a3.complaint_id=c3.id 
JOIN USER u3
  ON u3.id=a3.assigned_to
JOIN (SELECT complaint_id,
              MAX(id) id
           FROM complaint_status
           WHERE status=2
           AND value IN(1,2)
           GROUP BY complaint_id) cs9
  ON cs9.complaint_id=c3.id
  AND cs.id = cs9.id
WHERE u3.user_type=14
  AND a3.expiry IS NULL    
  AND cs.created_at >= DATE_SUB(CURRENT_DATE, INTERVAL DAYOFMONTH(CURRENT_DATE)-1 DAY)
  AND cs.created_at < DATE_ADD(LAST_DAY(CURRENT_DATE), INTERVAL + 1 DAY)
GROUP BY u3.id
ORDER BY COUNT(c3.id) DESC