SQLite SELECT 具有 max() 性能

Tox*_*iro 4 sqlite performance

我有一个大约有 150 万行和三列的表。列“timestamp”为 REAL 类型并已建立索引。我正在通过 PHP PDO 访问 SQLite 数据库。

以下三个选择的运行时间不到一毫秒:

select timestamp from trades
select timestamp + 1 from trades
select max(timestamp) from trades
Run Code Online (Sandbox Code Playgroud)

下面的选择大约需要半秒:

select max(timestamp) + 1 from trades
Run Code Online (Sandbox Code Playgroud)

这是为什么?

编辑:Lasse 要求“解释查询计划”,我已在 PHP PDO 查询中运行它,因为我目前没有直接的 SQLite3 命令行工具访问权限。我想这并不重要,结果如下:

explain query plan select max(timestamp) + 1 from trades:
    [selectid] => 0
    [order] => 0
    [from] => 0
    [detail] => SCAN TABLE trades (~1000000 rows)

explain query plan select max(timestamp) from trades:
    [selectid] => 0
    [order] => 0
    [from] => 0
    [detail] => SEARCH TABLE trades USING COVERING INDEX tradesTimestampIdx (~1 rows)
Run Code Online (Sandbox Code Playgroud)

Tim*_*sen 5

此查询的原因

select max(timestamp) + 1 from trades
Run Code Online (Sandbox Code Playgroud)

花费如此长的时间是因为查询引擎必须为每条记录计算MAX值,然后为其加一。计算该MAX值涉及执行全表扫描,并且必须对每条记录重复此操作,因为您要向该值加一。

在查询中

select timestamp + 1 from trades
Run Code Online (Sandbox Code Playgroud)

正在对每条记录进行计算,但引擎只需要扫描整个表一次。在这个查询中

select max(timestamp) from trades
Run Code Online (Sandbox Code Playgroud)

引擎确实必须扫描整个表,但也只扫描一次。

来自SQLite 文档

包含单个 MIN() 或 MAX() 聚合函数(其参数是索引最左边的列)的查询可以通过执行单个索引查找而不是扫描整个表来满足。

我在文档中强调了“可能”,因为看起来SELECT MAX(x)+1 FROM table 如果列x不是索引的最左边列,则对于形式的查询可能需要进行全表扫描。