mysql - 使用 GROUP BY 按时函数优化 MySQL 查询

标签 mysql database-design optimization query-optimization

我有以下查询:

SELECT location, step, COUNT(*), AVG(foo), YEAR(start), MONTH(start), DAY(start)
FROM table WHERE jobid = 'xxx' AND start BETWEEEN '2010-01-01' AND '2010-01-08'
GROUP BY location, step, YEAR(start), MONTH(start), DAY(start)

最初我在单个列上有索引,例如 jobidstart,但很快意识到 MySQL 在选择中只真正支持每个表的一个索引。因此,它将使用 jobid 索引,然后进行相当大的扫描以按 start 范围过滤掉。

在 (jobid, start) 上添加索引有很大帮助,但 GROUP BY 仍然会导致性能问题。我读过 docs on GROUP BY optimizations并了解为了从这些优化中受益,我需要一个包含(locationstepstart)的索引,但我还有两个开放式问题:

  1. group by 优化甚至可以使用时间函数(YEAR、MONTH、DAY 等)吗?还是我必须将这些值存储为单独的列?我喜欢执行这些功能的原因是,这意味着我可以在每个连接的基础上控制时区,并返回适合最终用户时区的结果。如果我必须预先存储年、月和日,我将通过 UTC 进行,然后我的所有用户将只获得 UTC 格式的报告。

  2. 即使我能解决问题 #1,我还能这样做吗?索引 (jobid, start) 有助于 WHERE 子句,但 GROUP BY 需要不同的索引进行优化 (location, step, start) 或者,根据 #1 的答案,(location, step, year)。但问题是这两个索引不共享一组公共(public)的左侧列,所以我不相信我的 WHERE 和 GROUP by 可以兼容,以至于使用相同的索引。所以我的问题是:我是不是刚被冲到这里?

关于如何实现这一目标的任何其他想法都会有所帮助。而且,只是为了抢占可能出现的一些问题/评论:

  1. 是的,这是一个时间序列数据集。
  2. 是的,它将受益于类似 RRDtool 的东西,但这样做会导致我失去执行特定时区的结果。
  3. 是的,预先计算汇总可能是个好主意,但我不需要出色的性能,所以如果允许的话,我可以接受良好的性能我为每个用户的时区自定义结果。

综上所述,如果有人对如何执行汇总或循环数据库之类的操作并仍然获得特定于时区的结果有任何设计建议,我洗耳恭听!


更新:根据要求,这里有更多信息:

显示输出的索引:

step    0   PRIMARY 1   step_id A   16  NULL    NULL        BTREE   
step    1   start   1   start   A   16  NULL    NULL        BTREE   
step    1   step    1   step    A   2   NULL    NULL        BTREE   
step    1   foo 1   foo A   16  NULL    NULL    YES BTREE   
step    1   location    1   location    A   2   NULL    NULL    YES BTREE   
step    1   jobid   1   jobid   A   2   NULL    NULL    YES BTREE   

显示创建表输出:

CREATE TABLE `step` (
  `start` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `step` smallint(2) unsigned NOT NULL,
  `step_id` int(8) unsigned NOT NULL AUTO_INCREMENT,
  `location` varchar(12) DEFAULT NULL,
  `jobid` varchar(37) DEFAULT NULL,
  PRIMARY KEY (`step_id`),
  KEY `start_time` (`start`),
  KEY `step` (`step`),
  KEY `location` (`location`),
  KEY `job_id` (`jobid`)
) ENGINE=InnoDB AUTO_INCREMENT=240 DEFAULT CHARSET=utf8

最佳答案

而不是这样做

GROUP BY location, step, YEAR(start), MONTH(start), DAY(start)
ORDER BY location, step, YEAR(start), MONTH(start), DAY(start)

尝试

GROUP BY location, step, date_format(start, '%Y%m%d')
ORDER BY location, step, date_format(start, '%Y%m%d')

关于mysql - 使用 GROUP BY 按时函数优化 MySQL 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4506431/

相关文章:

php - 过滤网页

mysql - 无法在 MySQL 中使用具有特定 GROUP BY 条件的 AVG 值进行 ORDER BY

php - 如何使用 Docker 连接 php-apache 和 MySQL?

mysql - 用于多对多关系统计分析的SQL数据库设计

mysql - 单个FK指来自多个表的PK

performance - 优化 "problems"在 libc 中的代码

mysql-相对于选择查询更新查询

SQL 主键,INT 或 GUID 或..?

javascript - 在 Javascript 中轻松添加值数组(例如,没有循环)

javascript - 在 JavaScript 中使用quadprog 进行投资组合优化约束错误