如何使用SQL有效地确定行之间的更改

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提供的工具优化它的最佳方法是什么?

最后一个约束是在将值插入数据表之前不对它们进行排序,并且它们可能在以后更新.这可能会影响任何可能的去规范化策略.

Dam*_*ver 3

你可以尝试这个 - 我不保证它会表现得更好,但这是我将行与“前一个”行关联起来的常用方法:

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),那么该候选确实是前一行。