(再次)检索 SQLite 表中的最后一条记录

Cat*_*oes 3 sql sqlite android

我先做了一些搜索,但仍然有一个问题。

远远地,我找到的最好的答案就在这个SO 答案中。总结:

SELECT * FROM TABLE WHERE ID = (SELECT MAX(ID) FROM TABLE);

我想知道的是下面的方法是否也同样有效(因为我懒得改变它,而且我碰巧喜欢它)。

SELECT * FROM TABLE ORDER BY ID DESC LIMIT 1

根据我们拥有的SQLite 自动增量文档,

如果插入时未指定 ROWID,或者指定的 ROWID 值为 NULL,则会自动创建适当的 ROWID。通常的算法是为新创建的行指定一个比插入之前表中最大 ROWID 大 1 的 ROWID。如果表最初为空,则使用 ROWID 1。[强调]

并进一步,

只要您从不使用最大 ROWID 值并且从不删除表中具有最大 ROWID 的条目,上述普通 ROWID 选择算法就会生成单调递增的唯一 ROWID。如果您删除了行或者创建了具有最大可能 ROWID 的行,则在创建新行时可能会重用以前删除的行中的 ROWID,并且新创建的 ROWID 可能不会严格按升序排列。 [强调]

我对我提出的 SQL 语句的疑问来自最后一句话。这似乎表明,如果删除任何行,则可以重用之前删除的 ROWID,无论是否已使用最大 ROWID。如果我们假设最大 ROWID 从未被使用过(手动或仅被那么多记录使用),那么我们只需要担心删除记录。在这种情况下,第一个 SQLite 文档摘录听起来好像您不会在我的查询中遇到任何问题。

有人有确切消息么?

我喜欢我的查询,因为它只涉及一个选择(尽管以订单为代价)。我想,我可能过于关注微小的优化,不是吗?

编辑:实际上,重新查看上面引用的 SQLite 页面,我认为使用 AUTOINCRMENT 关键字可以保证单调递增的 ROWID。最后一节详细讨论了这一点。

如果列的类型为 INTEGER PRIMARY KEY AUTOINCRMENT,则使用略有不同的 ROWID 选择算法。为新行选择的 ROWID 至少比同一表中以前存在的最大 ROWID 大 1。如果表之前从未包含任何数据,则使用 ROWID 1。如果表之前已经保存了具有最大可能 ROWID 的行,则不允许进行新的 INSERT,并且任何插入新行的尝试都将失败并出现 SQLITE_FULL 错误。

现在对我来说似乎很清楚。只是无法填满表格(最多 9223372036854775807)。

抱歉,我之前只浏览了这一部分!

小智 5

我想我应该在这里记录一下这两个查询运行的速度。
在一张大约有 15,000 行的表上,抓取其中的 1400 行,然后获取最后输入的行,以下是我得到的结果:

SELECT macAddr, time, onPeakTotalIn, onPeakTotalOut, offPeakTotalIn, offPeakTotalOut FROM trafficMon WHERE macAddr="02:d2:ee:aa:aa:aa" ORDER BY time DESC LIMIT 1;
Run Code Online (Sandbox Code Playgroud)

CPU 时间: user 0.008124 sys 0.000000
虚拟机步骤: 58741
全扫描步骤: 14156

SELECT macAddr, time, onPeakTotalIn, onPeakTotalOut, offPeakTotalIn, offPeakTotalOut FROM trafficMon WHERE id = (SELECT MAX(id) FROM trafficMon WHERE macAddr="02:d2:ee:aa:aa:aa");
Run Code Online (Sandbox Code Playgroud)

CPU 时间: user 0.000295 sys 0.000000
虚拟机步骤: 49
全扫描步骤: 3

正如您所看到的,明智地执行 MAX(id) 资源要容易得多,并且花费的时间要少得多。

虽然 0.008124s 一直都是问题,但当您在基于 MIPS 的嵌入式设备(在我的例子中是路由器)上运行相同的命令时,在脚本中与一堆其他东西一起运行它 20-30 倍,这一切都会加起来。