【问题标题】:SQLite3 How to calculate differential changesSQLite3 如何计算差异变化
【发布时间】:2016-02-12 08:23:34
【问题描述】:

我有一个中等大小的数据库(当时 400,000 行),其中包含一个具有以下架构的测量表:

CREATE TABLE `Measurements` (
`timestamp` timestamp,
`timetick`  INTEGER,
`Sensor1`   REAL,
`Sensor2`   REAL,
PRIMARY KEY(timestamp));

随着时间戳增加(时间戳增加不是恒定的,存在间隙和延迟,但时间戳保证是单调的),通常时间戳也会增加,但在某些情况下它会重置为一个小但不可预测的值。我需要找到所有这样的行。我使用了以下查询(灵感来自Finding the difference in rows in query using SQLite):

select r0,r1,a,b,rd,d from 
(select M0.rowid as r0,
  M1.rowid as r1,
  M0.timestamp as a,
  M1.timestamp as b,
  min(M1.timestamp)-M0.timestamp as rd,
  M1.timetick-M0.timetick as d
  from Measurements M0,Measurements M1
  where M1.timestamp>M0.timestamp group by M0.timestamp
) where d<0;

这可行,但需要几个小时,而 python 中的相同工作在 30 秒内完成。然而,这是一项非常常见的任务,科学家一直在计算衍生品,而金融专业人士则在计算价格差异。应该有一种有效的方法来做到这一点。
感谢您的帮助和 cmets。

【问题讨论】:

  • 显示EXPLAIN QUERY PLAN的输出。
  • @cl 0|0|0|SCAN TABLE Measurements AS M0 USING INDEX sqlite_autoindex_Measurements_1 (~1000000 行) 0|1|1|SEARCH TABLE Measurements AS M1 USING INDEX sqlite_autoindex_Measurements_1 (timestamp>?) (~ 250000 行)
  • 在 SQL 中,您可以使用 LAG 来查看以前的记录。 SQLite 虽然没有这个分析功能。这意味着它无法处理排序列表并轻松比较相邻行。这是可能的,但会涉及带有大量中间结果的连接,因此对于 DBMS 来说是一项艰苦的工作。因此,您最好使用编程语言(正如您已经注意到的那样)。
  • @Thorsten Kettner:虽然在我的例子中@CL 提供了一个有效的查询,但在尝试理解它时,我注意到细微的变化会创建数据库引擎无法优化的查询,因此执行时间很长.所以我完全同意你的观点,最好坚持使用我更熟悉的语言。

标签: sql sqlite


【解决方案1】:

带有 GROUP BY 的连接很难优化。

最好使用相关子查询来查找相应的下一行:

SELECT m0.rowid AS r0,
       m1.rowid AS rn,
       m0.timestamp AS a,
       m1.timestamp AS b,
       m1.timestamp - m0.timestamp AS rd,
       m1.timetick - m0.timetick AS d
FROM (SELECT rowid,     -- This is the core query attaching to each row
             timestamp, -- the rowid of its next
             timetick,
             (SELECT rowid
              FROM measurements
              WHERE timestamp > m.timestamp
              ORDER BY timestamp
              LIMIT 1
             ) AS r1
      FROM Measurements AS m
     ) AS m0
JOIN measurements AS m1 ON m0.r1 = m1.rowid
WHERE m1.timetick - m0.timetick < 0;

如果时间戳是整数,则将该列设为 INTEGER PRIMARY KEY 以避免额外的索引查找。

【讨论】:

  • 谢谢,时间戳不是整数。此查询非常快,但不会产生正确的结果,可能是因为行 ID 递增的行并不总是具有递增的时间戳 - 测量值在不同的计算机中收集并合并。我不希望每次添加测量值时都将整个表复制到一个新表中,以确保增加 rowid 意味着增加时间戳(除非我必须这样做,或者可能在 python 中这样做)
  • 编辑问题以显示一些示例数据和所需的结果。
  • 我觉得我需要包含所有数据来显示问题,我可以做到(它们是室温测量值)但 db 是 40MB。只有 14 种情况会重置计时器
  • 我很抱歉,查询工作正常,看似不正确的结果是由于缺少 timetick 值的行。执行时间小于5sec,比python版本快5倍。我还能够过滤掉缺少时间标记的行。
  • 请您解释一下在最里面的选择中定义 AS r1 的目的是什么,以及它是否与顶部选择中的 r1 相关。名称 m0 也被赋予 2 个不同的实体,这是必要的吗?谢谢。
猜你喜欢
  • 1970-01-01
  • 2016-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多