使用UNIONS优化MySQL查询

时间:2012-11-29 17:39:06

标签: mysql union

我有一个查询(可行),以显示包含特定关键字的邮件的平均回复数。

但我认为它可以被优化 - 我们担心随着数据库的增长,这个查询会变得非常慢,特别是如果我们使用更大的日期范围。

以下是当前查询的示例:

SELECT 'text1' AS "text", ROUND(AVG (a.rt_count),2) AS "Average over 100 days"
FROM 
(SELECT COUNT(reply.id) AS rt_count
FROM message LEFT OUTER JOIN reply ON (message.id = reply.message)
WHERE message.text LIKE '%text1%'
AND message.created_date >= (CURDATE() - INTERVAL 100 DAY)
GROUP BY message.id
) AS a
UNION
SELECT 'text2' AS "text", ROUND(AVG (a.rt_count),2) AS "Average over 100 days"
FROM 
(SELECT COUNT(reply.id) AS rt_count
FROM message LEFT OUTER JOIN reply ON (message.id = reply.message)
WHERE message.text LIKE '%text2%'
AND message.created_date >= (CURDATE() - INTERVAL 100 DAY)
GROUP BY message.id
) AS a 
UNION
SELECT 'text3' AS "text", ROUND(AVG (a.rt_count),2) AS "Average over 100 days"
FROM 
(SELECT COUNT(reply.id) AS rt_count
FROM message LEFT OUTER JOIN reply ON (message.id = reply.message)
WHERE message.text LIKE '%text3%'
AND message.created_date >= (CURDATE() - INTERVAL 100 DAY)
GROUP BY message.id
) AS a 

正如您所看到的,唯一真正改变的是WHERE message.text LIKE '%text1%',这会增加许多冗余代码。任何优化想法? - 所有建议非常感谢

2 个答案:

答案 0 :(得分:1)

SELECT case when message.text like '%text1%'
            then 'text1'
            when message.text like '%text2%'
            then 'text2'
            when message.text like '%text3%'
            then 'text3'
       end AS "text", 
       ROUND(AVG (a.rt_count),2) AS "Average over 100 days"
FROM 
(SELECT COUNT(reply.id) AS rt_count
FROM message LEFT OUTER JOIN reply ON (message.id = reply.message)
WHERE (message.text like '%text1%'
or message.text like '%text2%'
or message.text like '%text3%')
AND message.created_date >= (CURDATE() - INTERVAL 100 DAY)
GROUP BY message.id
) AS a 

答案 1 :(得分:0)

要使您的查询效果更好,请使用UNION ALL代替UNION。这将消除不必要的消除重复的步骤。

如果一行最多可以匹配一个文本,那么以下内容将起作用:

SELECT MatchText AS "text", ROUND(AVG (a.rt_count),2) AS "Average over 100 days"
FROM (SELECT MatchText, m.Id, COUNT(reply.id) AS rt_count
      FROM (select m.*,
                   (case when m.text like '%text1%' then 'Text1'
                         when m.text like '%text2%' then 'Text2'
                         when m.text like '%text3%' then 'Text3'
                    end) as MatchText
            from message m
           ) m LEFT OUTER JOIN
           repl
           ON (m.id = reply.message)
      WHERE MatchText is not NULL AND
            message.created_date >= (CURDATE() - INTERVAL 100 DAY)
      group by MatchText, m.Id
     ) t
group by MatchText