我有以下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按降序排序
答案 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)如果您对表进行分区,那么一段时间后将很难管理,因为拥有数百个分区并不好,并且一天的业务会给当前数据结构带来非常“不舒服”的任务,这将导致重新思考表模式。
解决方案是重新考虑您的逻辑:
clicks
表中(该表不应该具有索引来快速插入)。clicks_by_markets
,clicks_by_markets_yearly
, clicks_by_markets_weekly
,clicks_by_markets_daily
另一种解决方案(没有Kafka):
clicks_raw
来放置请求数据而不进行处理。clicks_raw
表并填充表,例如:clicks_by_markets
,clicks_by_markets_yearly
,clicks_by_markets_weekly
,clicks_by_markets_daily