0

ここで私の合理化された状況

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');

次に、IDの選択リストのテーブルt1を出力することを目的とする外部SELECTがあります(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 はその制限制約で核攻撃します。

私の質問は、クエリ オプティマイザーがこの外側の制限制約を検出し、それを内側の選択に伝達するかどうかです。

答えが NO の場合は、さらに一歩進んで、クエリ ジェネレーターが、このように内側の 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 を見ましたが、これは私の知識を超えており、そこから回答できませんでした。

4

1 に答える 1

1

SQLite にはLIMIT 句をサブクエリに移動できる最適化がなく、サブクエリのフラット化は IN 句には適用されません。

これは EXPLAIN で確認されます (addr 22 は外側のループにあります)。

sqlite> 説明 select d from t1 where i in (select i from t2 where e>'b') limit 4;
addr opcode p1 p2 p3 p4 p5 コメント
---- ------------- ---- ---- ---- ------------- -- ------ -------
0 初期化 0 26 0 00 26 から開始
1 整数 4 1 0 00 r[1]=4; リミットカウンター
2 OpenRead 0 2 0 2 00 root=2 iDb=0; t1
3 巻き戻し 0 24 0 00
4 Noop 0 0 0 00 begin IN expr
5 1 回 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 巻き戻し 1 15 0 00
9 列 1 1 2 00 r[2]=t2.e
10 Le 3 14 2 (BINARY) 52 if r[3]<=r[2] goto 14
11 列 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 キー=r[5]
14 次へ 1 9 0 01
15 クローズ 1 0 0 00
16 列 0 0 2 00 r[2]=t1.i
17 IsNull 2 23 0 00 if r[2]==NULL goto 23
18 アフィニティ 2 1 0 C 00 アフィニティ(r[2])
19 NotFound 3 23 2 1 00 キー = r[2]; end IN expr
20 列 0 1 6 00 r[6]=t1.d
21 ResultRow 6 1 0 00 出力=r[6]
22 DecrJumpZero 1 24 0 00 if (--r[1])==0 goto 24
23 次へ 0 4 0 01
24 クローズ 0 0 0 00
25 停止 0 0 0 00
26 トランザクション 0 0 2 0 01 usesStmtJournal=0
27 テーブルロック 0 2 0 t1 00 iDb=0 root=2 write=0
28 テーブルロック 0 3 0 t2 00 iDb=0 root=3 write=0
29 文字列 8 0 3 0 b 00 r[3]='b'
30 後藤 0 1 0 00

行のランダムなサンプルが実際に必要でない限り、ORDER BY 句のない LIMIT はおそらくあまり役​​に立たないことに注意してください。

于 2016-07-20T06:50:35.427 に答える