AWS RDS MySql 具有复合索引和日期范围的简单查询在大约 800 万个数据中执行时间过长
Posted
技术标签:
【中文标题】AWS RDS MySql 具有复合索引和日期范围的简单查询在大约 800 万个数据中执行时间过长【英文标题】:AWS RDS MySql Simple query with composite index and date range took too long to execute out of ~8 millions data 【发布时间】:2020-04-16 17:50:49 【问题描述】:查询非常简单,即
SELECT
col1 , date_col
FROM table USE INDEX (device_date_col)
WHERE
device_id = "some_value"
AND date_col BETWEEN "2020-03-16 00:00:00" and "2020-04-16 00:00:00"
limit 1000000 ;
但第一次运行时最终返回结果需要 30 到 60 秒。然后它在 10 秒内返回结果。另一个问题是,当我再次更改 device_id 时,需要很长时间。除了使用正确的索引之外,我无法理解为什么会发生这种情况。
我们知道,由于我们的 API 遇到超时,API 网关有 30 秒的限制。从今天起突然发生。
主要目标是检索微小的数据,它返回的数据较少但也需要很长时间,即
....
AND col1 IS NOT NULL
GROUP BY
DATE(date_col),
HOUR(date_col),
MINUTE(date_col)
以下是一些有用的信息
-
AWS RDS 具有实例 db.m4.large(vCPU 2 和 RAM 8GB)。
mysql 版本 5.6.x
date_col 和 device_col 上的复合索引
使用 InnoDB
表没有id字段(主键)
表中的总行数为 750 万
每台设备每 3 秒有一次数据
查询返回大约 600k 的行
解释查询显示它正在使用索引
更新
MySql Workbench 显示,当我在没有 group by 的情况下运行查询时,执行需要 2 秒,但检索时间 > 30 秒,当我使用 group by 时,服务器需要 > 30 来执行但检索需要 2 秒。
我认为我们需要更多
下图显示了没有分组依据的查询响应。查看持续时间/获取时间
【问题讨论】:
你试过不使用索引吗?您处于它对您的情况有用的边缘,请参见例如here。尝试删除USE INDEX (device_date_col)
,或者,最有希望的是,在索引中包含 col1,例如添加索引(device_id, date_col, col1)
。第二次运行比第一次运行更快是由于数据在内存中,而不必从磁盘读取。除了增加缓冲池(这可能需要您获得更多内存)或确保所有数据都在内存中(通过之前使用它)之外,您无能为力。
@Solarflare 我已经更新了问题,请您查看并建议我的假设?
我们已经确保第一个查询不应该超时,即它必须在 30 秒以下。
SQL_NO_CACHE 未按预期工作。每次我运行查询时,时间总是比以前少,这让我相信它仍然显示缓存的结果。还尝试了 RESET QUERY CACHE;刷新查询缓存;
@Solarflare,我已经按照您的建议创建了新索引(device_id、date_col、col1)。在有/没有 group by 的情况下,现在似乎工作正常。谢谢
【参考方案1】:
(原始查询)
SELECT col1 , date_col
FROM table USE INDEX (device_date_col)
WHERE device_id = "some_value"
AND date_col BETWEEN "2020-03-16 00:00:00"
AND "2020-04-16 00:00:00"
limit 1000000 ;
INDEX(device_id, date_col, col1)
的讨论
-
以
=
列、名称、y device_id
开始索引。这在一定程度上集中了搜索。
在此范围内,进一步关注日期范围。因此,将date_col
添加到索引中。您现在拥有WHERE
的最佳索引
如果列数不多且不包含TEXT
列,则添加SELECT
中任何位置显示的所有其他列。现在你有了一个“覆盖”索引。这允许仅使用索引的BTree
执行查询,从而进一步提高速度。
更多讨论:http://mysql.rjweb.org/doc.php/index_cookbook_mysql
其他说明
没有ORDER BY
的LIMIT
通常是没有意义的——你有可能得到一组随机的行。
BETWEEN
包含一个额外的午夜。我建议
AND date_col >= "2020-03-16"
AND date_col < "2020-03-16" + INTERVAL 1 MONTH
删除USE INDEX
-- 今天可能会有所帮助,但明天可能会在数据更改或常量更改时造成伤害。
LIMIT 1000000
-- 这可能会让一些客户窒息。你真的需要那么多行吗?或许可以在数据库中进行更多处理?
添加GROUP BY
-- 在某些分钟内col1
是否有两个值?你会得到col1
的哪个值?考虑MAX(col1)
、ANY_VALUE(col1)
或GROUP_CONCAT(DISTINCT col1)
。
【讨论】:
以上是关于AWS RDS MySql 具有复合索引和日期范围的简单查询在大约 800 万个数据中执行时间过长的主要内容,如果未能解决你的问题,请参考以下文章