我有一个包含700万行(每月将增长1000万)用户流量的mysql表,我需要对其进行实时分析。该表有多个列,但结果集中只需要一列。
这是查询:
SELECT DISTINCT visitor
FROM traffic
WHERE `visited` < '2019-03-01' AND `client_id` = 1 AND `country` IS NOT NULL
此查询需要15秒钟来执行,目前要处理700万行。我在visitor
,visited
,client_id
和country
上有单独的索引,在[visited
,client_id
和{ {1}}]。
所有索引都不是唯一的,也不是唯一的。
你们能想到我可以减少此查询执行时间的任何方式吗?
答案 0 :(得分:0)
在这个答案中,我将假设访问的是文本数据,例如varchar,因为我们看到client_id是数字,并且在国家(地区)的情况下,我们只想查看它是否具有值。如果假设访问的文本是正确的,则解决方案是将其类型更改为DATE,DATETIME或TIMESTAMP。由于在这种情况下我们似乎对时间不感兴趣,因此拥有DATE列应该是最热门的候选人。
解决方案(确保涉及交易):
在表中创建一个访问过的具有相同类型的temp_visited列
将访问的值复制到temp_visited
将已访问值设置为null或删除已访问列(无论您需要什么)
确保您拥有DATE类型的访问列
通过将文本值转换为DATE将值从temp_visited复制到Visited中
删除临时访问的列
答案 1 :(得分:0)
数据仓库通常会请求汇总表。
如果您构建并维护包含以下列的摘要表,则该查询(或者更确切地说是打入摘要表的变体)的运行速度会大大提高:
visited
-到一天(或一个月?)country
-也许把那些没有国家的人排除在外?client_id
visitor
COUNT(*)
SUM()
是什么东西?对于PARTITIONing
,如果您要清除“旧”行,可能仅有用。
对于当前查询,最佳索引将是
INDEX(client_id, visited, -- this much will be used in the `WHERE`
country, visitor) -- to make the index "covering"
单列索引实际上将毫无用处。由于“覆盖”,我的4列索引将明显优于任何3列索引。这意味着查询可以在索引内部运行,而不必到达数据的BTree。