我有这样的数据库(实际上有超过30个不同的sKey):
+----+------+------+---------------------+
|ID | sKey | sVal | timestamp |
+----+------+------+---------------------+
| 1 | temp | 19 | 2023-07-14 20:32:06 |
| 2 | humi | 60 | 2023-07-14 20:33:06 |
| 3 | temp | 20 | 2023-07-14 20:34:06 |
| 4 | humi | 65 | 2023-07-14 20:35:06 |
| 5 | pres | 1023 | 2023-07-14 20:36:06 |
| 6 | temp | 22 | 2023-07-14 20:37:06 |
| 7 | temp | 21 | 2023-07-14 20:38:06 |
| 8 | pres | 1028 | 2023-07-14 20:39:06 |
| 9 | temp | 20 | 2023-07-14 20:40:06 |
|10 | temp | 19 | 2023-07-14 20:43:06 | <-time glitch
|11 | pres | 1022 | 2023-07-14 20:44:06 |
|12 | temp | 19 | 2023-07-14 20:45:06 |
|13 | humi | 66 | 2023-07-14 20:46:06 |
|14 | humi | 63 | 2023-07-14 20:47:06 |
|15 | temp | 19 | 2023-07-14 20:48:06 |
|16 | pres | 1029 | 2023-07-14 20:49:06 |
|20 | temp | 19 | 2023-07-14 20:50:06 | <- ID not consecutive (deleted records)
|21 | pres | 1022 | 2023-07-14 20:61:06 |
|22 | temp | 19 | 2023-07-14 20:62:06 |
|23 | pres | 1029 | 2023-07-14 20:63:06 |
+----+------+------+---------------------+
现在我希望获得每个 sKey 的平均值(值以 sVal 为单位)。 现在我有可行的解决方案,但速度很慢。实际上我有 3 个独立的查询,如下所示:
SELECT AVG(`sVal`), `timestamp` FROM `Test` WHERE sKey='temp' AND timestamp between '2023-07-14 20:34:06' and '2023-07-14 20:51:06' GROUP BY FLOOR(TO_SECONDS(`timestamp`)/180)
SELECT AVG(`sVal`), `timestamp` FROM `Test` WHERE sKey='humi' AND timestamp between '2023-07-14 20:34:06' and '2023-07-14 20:51:06' GROUP BY FLOOR(TO_SECONDS(`timestamp`)/180)
SELECT AVG(`sVal`), `timestamp` FROM `Test` WHERE sKey='pres' AND timestamp between '2023-07-14 20:34:06' and '2023-07-14 20:51:06' GROUP BY FLOOR(TO_SECONDS(`timestamp`)/180)
由于数据库目前已经有超过2000000条记录,单次查询大约需要3秒。我假设如果我可以以某种方式将查询连接到仅一个 WHERE sKey=... 结果应该会更快。那么如何改进呢。
或者也许我的方法根本就是错误的。想要的结果是获得每个 sKey 的平均 sVal。平均间隔不能以记录编号(ID)为单位,因为某些记录可能会被删除。即使 ID 在行中,也可能会丢失一些记录。所以我认为只能使用时间戳本身的间隔。但我是 SQL 新手,我可能会错过一些东西。
您可以使用条件平均值
SELECT
AVG(IF(sKey = 'temp', `sVal`, 0)) AS `temp`,
AVG(IF(sKey = 'humi', `sVal`, 0)) AS `humi`,
AVG(IF(sKey = 'pres', `sVal`, 0)) AS `pres`,
MIN(`timestamp`) As `timestamp`
FROM
`Test`
WHERE
timestamp BETWEEN '2023-07-14 20:34:06' AND '2023-07-14 20:51:06'
GROUP BY FLOOR(TO_SECONDS(`timestamp`) / 180);