cg.*_*cg. 5 mysql sql optimization query-optimization
我有一个非常大的MySQL表,包含从许多传感器读取的数据.基本上,有一个时间戳和一个值列.我将省略传感器ID,在此处索引其他详细信息:
CREATE TABLE `data` (
`time` datetime NOT NULL,
`value` float NOT NULL
)
Run Code Online (Sandbox Code Playgroud)
该value
列很少更改,我需要找到发生这些更改的时间点.假设每分钟都有一个值,以下查询将返回我需要的内容:
SELECT d.*,
(SELECT value FROM data WHERE time<d.time ORDER by time DESC limit 1)
AS previous_value
FROM data d
HAVING d.value<>previous_value OR previous_value IS NULL;
+---------------------+-------+----------------+
| time | value | previous_value |
+---------------------+-------+----------------+
| 2011-05-23 16:05:00 | 1 | NULL |
| 2011-05-23 16:09:00 | 2 | 1 |
| 2011-05-23 16:11:00 | 2.5 | 2 |
+---------------------+-------+----------------+
Run Code Online (Sandbox Code Playgroud)
唯一的问题是这是非常低效的,主要是由于依赖子查询.使用MySQL 5.1提供的工具优化它的最佳方法是什么?
最后一个约束是在将值插入数据表之前不对它们进行排序,并且它们可能在以后更新.这可能会影响任何可能的去规范化策略.
你可以尝试这个 - 我不保证它会表现得更好,但这是我将行与“前一个”行关联起来的常用方法:
SELECT
* --TODO, list columns
FROM
data d
left join
data d_prev
on
d_prev.time < d.time --TODO - Other key columns?
left join
data d_inter
on
d_inter.time < d.time and
d_prev.time < d_inter.time --TODO - Other key columns?
WHERE
d_inter.time is null AND
(d_prev.value is null OR d_prev.value <> d.value)
Run Code Online (Sandbox Code Playgroud)
(我认为这是正确的 - 可以用一些示例数据来验证它)。
基本上,其想法是将表连接到其自身,并为每一行(在 中)查找“前一”行的d
候选行(在 中)。d_prev
然后进行进一步的联接,尝试查找d_inter
当前行 (in d
) 和候选行 (in ) 之间存在的行 (in d_prev
)。如果我们找不到这样的行 ( d_inter.time is null
),那么该候选确实是前一行。