如何在mysql数据库中有效地存储和搜索每分钟的数据?

如何在mysql数据库中有效地存储和搜索每分钟的数据?,mysql,performance,Mysql,Performance,我试着记录每分钟200个功率表。每个功率计都有唯一的IDPMID。模式如下所示: CREATE TABLE `pmd` ( `datatime` datetime NOT NULL, `pmid` smallint(5) unsigned NOT NULL, `statusid` tinyint(3) unsigned NOT NULL, `I1` double NOT NULL, `I2` double NOT NULL, `I3` double NOT NULL,

我试着记录每分钟200个功率表。每个功率计都有唯一的IDPMID。模式如下所示:

CREATE TABLE `pmd` (
  `datatime` datetime NOT NULL,
  `pmid` smallint(5) unsigned NOT NULL,
  `statusid` tinyint(3) unsigned NOT NULL,
  `I1` double NOT NULL,
  `I2` double NOT NULL,
  `I3` double NOT NULL,
  `I0` double NOT NULL,
  PRIMARY KEY (`datatime`,`pmid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
我的用例是检索特定功率计的hourlywhere-minute=0、daily-where-hour&minute=0和Monthly-recordwhere-day=1&hour&minute=0

在前两个月内,查询工作正常且快速。但是,记录越多,查询时间就变得非常慢

我想征求意见,如何提高绩效? 我心里有一些想法: 1.将datetime更改为分隔字段,如:

`year_2digit` tinyint NOT NULL,
`month` tinyint NOT NULL,
`day` tinyint NOT NULL,
`hour` tinyint NOT NULL,
`minute` tinyint NOT NULL,
2.为每个月创建新表。
更新:今天我在网上读了更多,有一种叫做分区的技术。我对它感兴趣,因为它不会改变模式。我想按年份和月份划分。我可以听听您对分区的看法吗?

您的第一个想法是我可能也会做的事情,但有一些小的例外:

而不是

`year_2digit` tinyint
我会用

`year` year
年份数据类型的存储大小与TINYINT 1字节相同

保留datatime列。其他查询可能需要它。例如,在MySQL中,一个有效的范围条件(如BETWEEN)是一个具有多个列的噩梦

最新的MySQL和MariaDB版本支持生成虚拟列。您可以使用该功能自动从datetime列生成值。如果您的版本不支持它,我将使用触发器

定义分钟、小时、日、月、年的综合指数。它将支持以下所有条件:

WHERE `minute` = 0
WHERE `minute` = 0 AND `hour` = 0
WHERE `minute` = 0 AND `hour` = 0 and `day` = 1
WHERE `minute` = 0 AND `hour` = 0 and `day` = 1 AND `month` = 1
WHERE `minute` = 0 AND `hour` = 0 and `day` = 1 AND `month` = 1
  AND `year` BETWEEN `2010` AND `2020`
我的用例是检索特定功率计的hourlywhere-minute=0、daily-where-hour&minute=0和Monthly-recordwhere-day=1&hour&minute=0

第1部分-获得正确的PK

因为您正在寻找一个pmid,所以按照这个顺序设置主键pmid datetime。并使用InnoDB使PK与数据聚集在一起

这样,您需要的行就不会分散在整个表中,而是聚集在一起。至少每分钟一次

您的查询必须是以下形式:

WHERE pmid = <constant>
  AND `datetime` >= '2016-07-11'
  AND `datetime`  < '2016-07-11' + INTERVAL 3 DAY
  AND MINUTE(`datetime`) = 0
将此添加到以下位置:

插入新数据时:

INSERT INTO pmd
    (scale, pmd, `datetime`, ...)
    VALUES
    (...<see below>, $pmd, $datetime, ...)
我说的是半生不熟,但当我把这一切都打出来时,它似乎是一致的


如果您成功地进行了分区,那么您将赢得案例5奖-我已经寻找案例5好几年了。

问题似乎是缺少索引您的MySQL版本是什么?你的查询是什么?我的MySQL版本是5.7.18。我通常使用它来查找每小时记录:从pmd中选择*,其中pmid=2,数据时间为'2017-04-01 00:00'、'2017-04-01 00:01'、…、'2017-04-01 23:59'限制1440;在5.7.18中,您可以使用注意,您的复合索引应该与您所提到的相反,使用年、月、日、小时、分钟,这样您就可以进行更粗略的查询,例如关于年、月、日、小时的where子句,同时仍然可以开始使用此复合索引。@否您建议的索引也可能有用,但是没有固定的年份,在任何情况下都是无用的。
AND scale >= 2   -- to get hourly data
INSERT INTO pmd
    (scale, pmd, `datetime`, ...)
    VALUES
    (...<see below>, $pmd, $datetime, ...)
PRIMARY KEY(pmd, `datetime`, scale)