【问题标题】:AWS RDS MySql Simple query with composite index and date range took too long to execute out of ~8 millions dataAWS RDS MySql 具有复合索引和日期范围的简单查询在大约 800 万个数据中执行时间过长
【发布时间】: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)

以下是一些有用的信息

  1. AWS RDS 具有实例 db.m4.large(vCPU 2 和 RAM 8GB)。
  2. MySql 版本 5.6.x
  3. date_col 和 device_col 上的复合索引
  4. 使用 InnoDB
  5. 表没有id字段(主键)
  6. 表中的总行数为 750 万
  7. 每台设备每 3 秒有一次数据
  8. 查询返回大约 600k 的行
  9. 解释查询显示它正在使用索引

更新

MySql Workbench 显示,当我在没有 group by 的情况下运行查询时,执行需要 2 秒,但检索时间 > 30 秒,当我使用 group by 时,服务器需要 > 30 来执行但检索需要 2 秒。 我认为我们需要更多

  • CPU 使用 group by 处理数据
  • 更多内存用于提取所有数据(无分组)

下图显示了没有分组依据的查询响应。查看持续时间/获取时间

【问题讨论】:

  • 你试过不使用索引吗?您处于它对您的情况有用的边缘,请参见例如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 的情况下,现在似乎工作正常。谢谢

标签: mysql amazon-rds database-performance query-performance sqlperformance


【解决方案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)的讨论

  1. = 列、名称、y device_id 开始索引。这在一定程度上集中了搜索。
  2. 在此范围内,进一步关注日期范围。因此,将date_col 添加到索引中。您现在拥有WHERE 的最佳索引
  3. 如果列数不多且不包含TEXT 列,则添加SELECT 中任何位置显示的所有其他列。现在你有了一个“覆盖”索引。这允许仅使用索引的BTree 执行查询,从而进一步提高速度。

更多讨论:http://mysql.rjweb.org/doc.php/index_cookbook_mysql

其他说明

  • 没有ORDER BYLIMIT 通常是没有意义的——你有可能得到一组随机的行。
  • 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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-17
    • 2022-12-12
    • 1970-01-01
    • 1970-01-01
    • 2013-10-05
    • 2021-01-19
    • 1970-01-01
    相关资源
    最近更新 更多