如何优化慢速MySQL查询

时间:2018-10-08 08:44:59

标签: mysql sql group-by

我有以下MySQL查询,执行时间很长:

SELECT `market`.`name` AS `Markets`, count(*) * `clicks`.`cost` AS `Rev`
FROM `clicks`
INNER JOIN markets ON `clicks`.`market_id`= `markets`.`id`
WHERE clicks.created_date = `date1`
GROUP BY `markets`.`id`
ORDER BY `Rev` DESC

最初,它非常慢,但是后来我删除了多余的日期函数。仍然需要很长时间才能执行。有什么解决办法吗?

查询说明: 我从一个表中选择市场名称,从另一表中选择行数乘以成本。 市场ID在第一个表格“点击次数”中定义,我从“市场”表格中获取市场名称。然后,我按ID将市场分组,并通过Rev按降序排序

3 个答案:

答案 0 :(得分:2)

您的查询正在滥用MySQL 部分分组依据功能。您正在按市场分组,但是有一个杂散列clicks.cost未包含在汇总中。无论查询速度有多快,您都会得到不正确的结果。

您可以按以下方式修改查询:

SELECT market.name AS Markets, subqry.Rev FROM (
    SELECT market_id, SUM(cost) AS Rev
    FROM clicks
    WHERE created_date = 'some date'
    GROUP BY market_id
) AS subqry
INNER JOIN markets ON subqry.market_id = markets.id
ORDER BY Rev DESC

确定结果正确后,创建以下索引:

CREATE INDEX ix_clicks ON clicks (created_date, market_id, cost)

答案 1 :(得分:2)

大概是您打算的:

SELECT m.name AS Markets, SUM(c.cost) AS `Rev`
FROM clicks c INNER JOIN
     markets m
     ON c.market_id = m.id
WHERE c.created_date = ?
GROUP BY m.name
ORDER BY Rev DESC;

这对性能没有帮助。但是,clicks(created_date, market_id, cost)上的索引可能会为您带来所需的性能。

如果这不起作用,请尝试以下操作:

SELECT m.name AS Markets,
       (SELECT SUM(c.cost)
        FROM clicks c
        WHERE c.market_id = m.id AND c.created_date = ?
       ) AS `Rev`
FROM markets m
ORDER BY Rev DESC;

这将删除外部GROUP BY,这可能会大大提高性能。为此,索引应该稍有不同,clicks(market_id, created_date, cost)

答案 2 :(得分:-1)

我知道这不是问题的直接答案,如果您愿意,您可能会否决我(我了解人性,向其他思想家表示仇恨)。


但是我必须编写替代的正确方法来处理这样的逻辑系统,在这些逻辑系统中,我们每天都有大量数据,并且将来必须进行汇总报告,而不会出现性能问题。


不幸的是它是时间序列数据。

它会增长,并会损失您的性能。

对于短期,添加索引可能会解决您的问题。

但是在长期运行中会出现很多市场的情况下,每天的点击次数会〜100万次。“索引解决方法”不是好的解决方案

A)如果您为索引日期字段做索引,您将慢速插入。因为它每次都会在后台执行索引更新过程。

B)如果您对表进行分区,那么一段时间后将很难管理,因为拥有数百个分区并不好,并且一天的业务会给当前数据结构带来非常“不舒服”的任务,这将导致重新思考表模式。


解决方案是重新考虑您的逻辑:

  1. 使用Kafka并将您的点击数据插入其中。
  2. 将数据插入到clicks表中(该表不应该具有索引来快速插入)。
  3. 让一个工作人员从Kafka获取点击数据,进行数学运算,并按市场创建日,周,月,年等的汇总。通过创建表格:clicks_by_marketsclicks_by_markets_yearlyclicks_by_markets_weeklyclicks_by_markets_daily

另一种解决方案(没有Kafka):

  1. 具有表clicks_raw来放置请求数据而不进行处理。
  2. 创建每10分钟安排一次的脚本并处理clicks_raw表并填充表,例如:clicks_by_marketsclicks_by_markets_yearlyclicks_by_markets_weeklyclicks_by_markets_daily