如何修复慢更新查询

时间:2019-01-10 00:34:54

标签: mysql query-optimization

我正在使用以下查询填充表 来自大量读数的每日极端温度值。这里有33个温度计,每分钟读取一次读数。因此,每天大约有46K读数(即行)。但是每天只有33行被添加到extremes

最初,我曾想过每次插入新的读数时都会运行此查询,以便保持最新状态。但是,我很快发现此查询要花很长时间才能运行:在我的MacBook上,整整一天的读数为5½分钟。

我将对为什么它这么慢的一些见解非常感兴趣,也许是如何使这个查询更快,或者是更好的选择。注意extremes具有Sensor_IDDate作为主键,因为那是每一行的唯一特征。

谢谢!

insert into extremes(Date, Sensor_ID, `min`, `max`, `avg`)
    select date(DateTime) as `Date`, Sensor_ID as Sensor_ID,
        min(Value) as `min`, max(Value) as `max`, avg(Value) as `avg`
        from readings where date(`DateTime`) = date(NOW())
    group by date(DateTime), Sensor_ID
on duplicate key update 
    `min` = values(`min`), `max` = values(`max`), `avg` = values(`avg`);

根据要求,这是表格

CREATE TABLE `readings` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Sensor_ID` int(11) NOT NULL,
  `DateTime` datetime NOT NULL,
  `Value` double NOT NULL,
  PRIMARY KEY (`ID`),
  UNIQUE KEY `ID_UNIQUE` (`ID`),
  KEY `ID_idx` (`Sensor_ID`),
  CONSTRAINT `ID` FOREIGN KEY (`Sensor_ID`) REFERENCES `sensors` (`ID`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=54500039 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

CREATE TABLE `extremes` (
  `Date` datetime NOT NULL,
  `Sensor_ID` int(11) NOT NULL,
  `min` double DEFAULT NULL,
  `max` double DEFAULT NULL,
  `avg` double DEFAULT NULL,
  `updates` int(11) DEFAULT '0',
  PRIMARY KEY (`Date`,`Sensor_ID`),
  KEY `ID_idx` (`Sensor_ID`),
  CONSTRAINT `foo` FOREIGN KEY (`Sensor_ID`) REFERENCES `sensors` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

2 个答案:

答案 0 :(得分:2)

将索引添加到DateTime表的readings列中。

然后尝试以下SQL:

insert into extremes(Date, Sensor_ID, `min`, `max`, `avg`)
    select date(DateTime) as `Date`, Sensor_ID as Sensor_ID,
        min(Value) as `min`, max(Value) as `max`, avg(Value) as `avg`
        from readings where `DateTime` >= date_format(curdate(), '%Y-%m-%d 00:00:00')
    group by date(DateTime), Sensor_ID
on duplicate key update 
    `min` = values(`min`), `max` = values(`max`), `avg` = values(`avg`);

答案 1 :(得分:1)

UNIQUE KEY `ID_UNIQUE` (`ID`),

会减慢对readings的修改。它是冗余,因为“ PRIMARY KEY ”是唯一的密钥。放下它。

仅在要插入的一行而不是所有行上执行IODKU:

insert into extremes(Date, Sensor_ID, `min`, `max`)
    VALUES(... , ..., ..., ...)   -- Place constants here (from the sensor)
on duplicate key update 
    `min` = LEAST(`min`, values(`min`)),
    `max` = GREATEST(`max`, values(`max`);

然后每天晚上进行一次平均设置。

这样,您触摸的是1行,而不是1440。

另一种技术是收集读数一分钟,然后将其应用于单个查询中。

您有数百万个传感器吗?重新考虑为INT使用4字节的Sensor_ID;有较小的整数。

您在哪里找到那些传感器?我怀疑您是否需要超过FLOAT的7个有效数字(4个字节)而不是8个字节的DOUBLEs

我对数据类型的观点是-收缩数据也可以加快处理速度,尤其是当您遇到太多数据无法缓存到RAM中的时候。

短语:“ Sensor_ID和Date作为主键”表示存在两个不同的PK,这是不可能的。而是“ Sensor_ID和Date形成复合主键”。是的,那是您需要该桌子的地方。您将Date放在第一还是最后取决于您的典型SELECT是什么。

FOREIGN KEYs是另一项费用。每次执行插入操作时,都需要检查另一个表以验证ID是否存在。至此,您已经对代码进行了足够的调试; FK可以说是浪费。

avg 可以每分钟计算一次,但是(1)在一天结束之前它是毫无意义的;(2)它需要一个额外的列(带有计数) )。