Распространение ограничения запроса на подзапрос

Здесь моя упрощенная ситуация

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 для списка выбора идентификатора (i)

select d from t1 where i in (3,4) limit 4;
d
----
aa3
aa4

Идентификационный набор сгенерирован, поэтому я могу получить

select d from t1 where i in (3,4,1,6,7) limit 4;
d
----
aa1
aa3
aa4
aa6

Иногда набор идентификаторов является результатом внутреннего подзапроса 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 может генерировать большой список идентификаторов, который внешний выбор обнуляет со своим ограничением ограничения.

Мой вопрос заключается в том, определяет ли оптимизатор запросов это ограничение внешнего лимита и распространяет его во внутренний выбор?

Если ответ НЕТ, то мне нужно пройти лишнюю милю, и мой генератор запросов должен явно переместить ограничение limit во внутреннем 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, но это вне моего понимания и не смог ответить оттуда.

1 ответ

Решение

SQLite не имеет оптимизации, которая могла бы переместить предложение LIMIT в подзапрос, и уплощение подзапроса не применяется к предложениям IN.

Это подтверждается с помощью EXPLAIN (адрес 22 находится во внешнем цикле):

sqlite> объяснение, выберите d из t1, где i in (выберите i из t2, где e>'b'), предел 4;
addr код операции p1    p2    p3    p4             p5 комментарий ---  -------------  ----  ----  ----  -------------  --  -------------
0     Init           0     26    0                    00 Начало в 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 Один раз 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, если r[3]<=r[2] перейти к 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  key=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, если 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  output=r[6]
22      DecrJumpZero   1     24    0                    00  if (--r[1])==0 перейти к 24 23 Далее 0 4 0 01 24 Закрыть 0     0     0                    00
25 Остановить 0     0     0                    00
26 Транзакция 0 0 2 0 01 использует StmtJournal=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 Перейти к 0 1 0 00

Обратите внимание, что LIMIT без предложения ORDER BY, вероятно, не очень полезен, если вы на самом деле не хотите случайную выборку строк.

Другие вопросы по тегам