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)
此查询的原因
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不是索引的最左边列,则对于形式的查询可能需要进行全表扫描。