sqlite> explain query plan select max(utc_time) from RequestLog;
0|0|0|SEARCH TABLE RequestLog USING COVERING INDEX key (~1 rows) # very fast
sqlite> explain query plan select min(utc_time) from RequestLog;
0|0|0|SEARCH TABLE RequestLog USING COVERING INDEX key (~1 rows) # very fast
sqlite> explain query plan select min(utc_time), max(utc_time) from RequestLog;
0|0|0|SCAN TABLE RequestLog (~8768261 rows) # will be very very slow
虽然我分别使用min
和max
,但效果很好。但是,当我出于某种原因选择min
和max
时,sqlite会“忘记”索引。我可以做任何配置(我已使用Analyze
,它不起作用)?或者这种行为有什么解释吗?
sqlite> .schema
CREATE TABLE FixLog(
app_id text, __key__id INTEGER,
secret text, trace_code text, url text,
action text,facebook_id text,ip text,
tw_time datetime,time datetime,
tag text,to_url text,
from_url text,referer text,weight integer,
Unique(app_id, __key__id)
);
CREATE INDEX key4 on FixLog(action);
CREATE INDEX time on FixLog(time desc);
CREATE INDEX tw_time on FixLog(tw_time desc);
sqlite> explain query select min(time) from FixLog;
0|0|0|SEARCH TABLE FixLog USING COVERING INDEX time (~1 rows)
sqlite> explain query select max(time) from FixLog;
0|0|0|SEARCH TABLE FixLog USING COVERING INDEX time (~1 rows)
sqlite> explain query plan select max(time), min(time) from FixLog;
0|0|0|SCAN TABLE FixLog (~1000000 rows)
答案 0 :(得分:7)
这是sqlite查询优化器的一个已知问题,如下所述:http://www.sqlite.org/optoverview.html#minmax:
如果存在适当的指数,以下形式的查询将被优化为以对数时间运行:
SELECT MIN(x) FROM table; SELECT MAX(x) FROM table;
为了进行这些优化,它们必须以上面显示的形式出现 - 仅更改表和列的名称。不允许添加WHERE子句或对结果执行任何算术运算。结果集必须包含单个列。 MIN或MAX函数中的列必须是索引列。
UPDATE(2017/06/23):最近,这已经更新,可以通过索引查找来满足包含单个MAX或MIN的查询(允许像算术这样的事情);但是,他们仍然排除在一个查询中有多个这样的聚合运算符(因此MIN,MAX仍然会很慢):
通过执行单个索引查找而不是扫描整个表,可以满足包含单个MIN()或MAX()聚合函数的查询,该函数的参数是索引的最左列。例子:
SELECT MIN(x) FROM table; SELECT MAX(x)+1 FROM table;