这是我精简的情况
create table t1 (i integer, d text);
insert into t1 values (0,'aa0');
insert into t1 values (1,'aa1');
insert into t1 values (2,'aa2');
insert into t1 values (3,'aa3');
insert into t1 values (4,'aa4');
insert into t1 values (5,'aa5');
insert into t1 values (6,'aa6');
insert into t1 values (7,'aa7');
insert into t1 values (8,'aa8');
insert into t1 values (9,'aa9');
create table t2 (i integer, e text);
insert into t2 values (0,'aa0');
insert into t2 values (1,'ba1');
insert into t2 values (2,'aa2');
insert into t2 values (3,'ba3');
insert into t2 values (4,'aa4');
insert into t2 values (5,'ba5');
insert into t2 values (6,'aa6');
insert into t2 values (7,'ba7');
insert into t2 values (8,'aa8');
insert into t2 values (9,'ba9');
然后我有一个外部SELECT,其目的是打印出表t1以获取ID(i)的选择列表
select d from t1 where i in (3,4) limit 4;
d
----
aa3
aa4
生成ID集,因此我最终可以
select d from t1 where i in (3,4,1,6,7) limit 4;
d
----
aa1
aa3
aa4
aa6
有时,ID集是内部SELECT子查询的结果,如
select d from t1 where i in (select i from t2 where e>'b') limit 4;
d
----
aa1
aa3
aa5
aa7
在我的实际情况中,t1和t2很大,内部SELECT可以生成一个大的ID列表,外部选择将使用其限制约束。
我的问题是,查询优化器是否检测到这个限制约束并将其传播到内部选择中?
如果答案为否,那么我应该加倍努力,我的查询生成器,必须在内部SELECT中明确地移动限制约束
select d from t1 where i in (select i from t2 where e>'b' limit 4);
d
----
aa1
aa3
aa5
aa7
在询问之前我看了EXPLAIN和EXPLAIN QUERY PLAN,但这是我所不知道的,无法从那里回答。
答案 0 :(得分:1)
SQLite没有optimization可以将LIMIT子句移动到子查询中,子查询展平不适用于IN子句。
这是通过EXPLAIN确认的(addr 22在外循环中):
sqlite> explain select d from t1 where i in (select i from t2 where e>'b') limit 4; addr opcode p1 p2 p3 p4 p5 comment ---- ------------- ---- ---- ---- ------------- -- ------------- 0 Init 0 26 0 00 Start at 26 1 Integer 4 1 0 00 r[1]=4; LIMIT counter 2 OpenRead 0 2 0 2 00 root=2 iDb=0; t1 3 Rewind 0 24 0 00 4 Noop 0 0 0 00 begin IN expr 5 Once 0 16 0 00 6 OpenEphemeral 3 1 0 k(1,B) 00 nColumn=1 7 OpenRead 1 3 0 2 00 root=3 iDb=0; t2 8 Rewind 1 15 0 00 9 Column 1 1 2 00 r[2]=t2.e 10 Le 3 14 2 (BINARY) 52 if r[3]<=r[2] goto 14 11 Column 1 0 4 00 r[4]=t2.i 12 MakeRecord 4 1 5 C 00 r[5]=mkrec(r[4]) 13 IdxInsert 3 5 0 00 key=r[5] 14 Next 1 9 0 01 15 Close 1 0 0 00 16 Column 0 0 2 00 r[2]=t1.i 17 IsNull 2 23 0 00 if r[2]==NULL goto 23 18 Affinity 2 1 0 C 00 affinity(r[2]) 19 NotFound 3 23 2 1 00 key=r[2]; end IN expr 20 Column 0 1 6 00 r[6]=t1.d 21 ResultRow 6 1 0 00 output=r[6] 22 DecrJumpZero 1 24 0 00 if (--r[1])==0 goto 24 23 Next 0 4 0 01 24 Close 0 0 0 00 25 Halt 0 0 0 00 26 Transaction 0 0 2 0 01 usesStmtJournal=0 27 TableLock 0 2 0 t1 00 iDb=0 root=2 write=0 28 TableLock 0 3 0 t2 00 iDb=0 root=3 write=0 29 String8 0 3 0 b 00 r[3]='b' 30 Goto 0 1 0 00
请注意,没有ORDER BY子句的LIMIT可能不是很有用,除非你真的想要一个随机的行样本。