8

我正在构建一个大型数据库(数百万行)的前端。数据是不同公司负荷的用水量,表格如下所示:

id | company_id | datetime            | reading | used | cost
=============================================================
1  | 1          | 2012-01-01 00:00:00 | 5000    | 5    | 0.50
2  | 1          | 2012-01-01 00:01:00 | 5015    | 15   | 1.50
....

在前端,用户可以选择他们想要查看数据的方式,例如:6 小时增量、每日增量、每月等。快速执行此操作的最佳方法是什么。鉴于数据变化如此之大以及任何一组数据将被看到的次数,将查询数据缓存在 memcahce 或类似的东西中几乎没有意义,并且由于变量太多,无法预先构建数据。

我认为使用某种聚合聚合表可以使诸如readings,readings_6h之类的表readings_1d具有完全相同的结构,只是已经聚合。

如果这是一个可行的解决方案,那么使聚合表保持最新和准确的最佳方法是什么。除了来自仪表的数据外,该表是只读的。用户不必更新或写入它。

一些可能的解决方案包括:

1)坚持使用组/聚合函数进行查询

2)做一个基本的选择和保存

SELECT `company_id`, CONCAT_WS(' ', date(`datetime`), '23:59:59') AS datetime, 
MAX(`reading`) AS reading, SUM(`used`) AS used, SUM(`cost`) AS cost 
FROM `readings`
WHERE `datetime` > '$lastUpdateDateTime'
GROUP BY `company_id`

3)重复键更新(不确定如何在这里进行聚合,还要确保数据准确,不计算两次或丢失行。

INSERT INTO `readings_6h` ... 
SELECT FROM `readings` .... 
ON DUPLICATE KEY UPDATE .. calculate...

4) 其他想法/建议?

我目前正在执行选项 2,这需要大约 15 分钟将 +- 100k 行聚合成 +- 30k 行,超过 4 个表(_6h、_1d、_7d、_1m、_1y)

TL;DR 查看/存储大量无法有效缓存的报告的聚合数据的最佳方法是什么。

4

1 回答 1

11

这个功能最好由一个名为materialized view的特性来提供,遗憾的是 MySQL 缺少该特性。您可以考虑迁移到不同的数据库系统,例如 PostgreSQL。

有多种方法可以使用存储过程、触发器和事件来模拟 MySQL 中的物化视图。您创建一个更新聚合数据的存储过程。如果必须在每次插入时更新聚合数据,您可以定义一个触发器来调用该过程。如果数据必须每隔几个小时更新一次,您可以定义一个MySQL 调度程序事件或一个 cron 作业来完成它。

有一种组合方法,类似于您的选项 3,它不依赖于输入数据的日期;想象一下如果一些新数据来得太晚并且没有进入聚合会发生什么。(您可能没有这个问题,我不知道。)您可以定义一个将新数据插入“积压”的触发器,并让该过程仅从积压更新聚合表。

本文详细介绍了所有这些方法:http ://www.fromdual.com/mysql-materialized-views

于 2012-07-26T19:04:53.197 回答