mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-27 20:41:58 +03:00
Query planner optimization to detect empty tables in a join early and bail out
without doing excess work. FossilOrigin-Name: 58797e9bafa95709e0f706a15f42f93b409e2db5
This commit is contained in:
15
manifest
15
manifest
@ -1,5 +1,5 @@
|
||||
C Minor\senhancement\sto\smutex\stracing\son\sWin32.
|
||||
D 2017-02-15T18:30:57.375
|
||||
C Query\splanner\soptimization\sto\sdetect\sempty\stables\sin\sa\sjoin\searly\sand\sbail\sout\nwithout\sdoing\sexcess\swork.
|
||||
D 2017-02-15T22:36:15.061
|
||||
F Makefile.in edb6bcdd37748d2b1c3422ff727c748df7ffe918
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc 067a6766f800cc8d72845ab61f8de4ffe8f3fc99
|
||||
@ -477,7 +477,7 @@ F src/wal.h 06b2a0b599cc0f53ea97f497cf8c6b758c999f71
|
||||
F src/walker.c 91a6df7435827e41cff6bb7df50ea00934ee78b0
|
||||
F src/where.c 6397fab50fdbf9bde76c574ce07b3b776eb28b34
|
||||
F src/whereInt.h 2bcc3d176e6091cb8f50a30b65c006e88a73614d
|
||||
F src/wherecode.c 99a8ced164c75edf41b3a865a75381c9adb38b28
|
||||
F src/wherecode.c 677e95413c472c0b413023b6b69a47f40fce1b04
|
||||
F src/whereexpr.c 130cdd1a43af71b19755270fb1224874cf55158c
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
@ -676,6 +676,7 @@ F test/e_wal.test ae9a593207a77d711443ee69ffe081fda9243625
|
||||
F test/e_walauto.test 248af31e73c98df23476a22bdb815524c9dc3ba8
|
||||
F test/e_walckpt.test 28c371a6bb5e5fe7f31679c1df1763a19d19e8a0
|
||||
F test/e_walhook.test 4c0613a0c76e7a9d5c4c211e1b4cbcc1143914df
|
||||
F test/emptytable.test a38110becbdfa6325cd65cb588dca658cd885f62
|
||||
F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
|
||||
F test/enc2.test 83437a79ba1545a55fb549309175c683fb334473
|
||||
F test/enc3.test 6807f7a7740a00361ca8d0ccd66bc60c8dc5f2b6
|
||||
@ -1555,7 +1556,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 810d29320b853b3a01aa50d8f2a0bceacf79e0aa
|
||||
R 91fee55f54fe2e54254ba44f0240778d
|
||||
U mistachkin
|
||||
Z 72fbc76e1b27f40edc76050b0de83496
|
||||
P 830b9235673be55f0c932fb157de03725e648c25
|
||||
R 32e948726be0c8ec843ec4b81e44685b
|
||||
U drh
|
||||
Z 345aeb62ab5f52d0700dc3107ec5c535
|
||||
|
@ -1 +1 @@
|
||||
830b9235673be55f0c932fb157de03725e648c25
|
||||
58797e9bafa95709e0f706a15f42f93b409e2db5
|
@ -1062,6 +1062,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
Vdbe *v; /* The prepared stmt under constructions */
|
||||
struct SrcList_item *pTabItem; /* FROM clause term being coded */
|
||||
int addrBrk; /* Jump here to break out of the loop */
|
||||
int addrHalt; /* addrBrk for the outermost loop */
|
||||
int addrCont; /* Jump here to continue with next cycle */
|
||||
int iRowidReg = 0; /* Rowid is stored in this register, if not zero */
|
||||
int iReleaseReg = 0; /* Temp register to free before returning */
|
||||
@ -1103,6 +1104,11 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
VdbeComment((v, "init LEFT JOIN no-match flag"));
|
||||
}
|
||||
|
||||
/* Compute a safe address to jump to if we discover that the table for
|
||||
** this loop is empty and can never contribute content. */
|
||||
for(j=iLevel; j>0 && pWInfo->a[j].iLeftJoin==0; j--){}
|
||||
addrHalt = pWInfo->a[j].addrBrk;
|
||||
|
||||
/* Special case of a FROM clause subquery implemented as a co-routine */
|
||||
if( pTabItem->fg.viaCoroutine ){
|
||||
int regYield = pTabItem->regReturn;
|
||||
@ -1287,7 +1293,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
sqlite3ExprCacheAffinityChange(pParse, r1, 1);
|
||||
sqlite3ReleaseTempReg(pParse, rTemp);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrBrk);
|
||||
sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrHalt);
|
||||
VdbeCoverageIf(v, bRev==0);
|
||||
VdbeCoverageIf(v, bRev!=0);
|
||||
}
|
||||
@ -1933,7 +1939,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
codeCursorHint(pTabItem, pWInfo, pLevel, 0);
|
||||
pLevel->op = aStep[bRev];
|
||||
pLevel->p1 = iCur;
|
||||
pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk);
|
||||
pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrHalt);
|
||||
VdbeCoverageIf(v, bRev==0);
|
||||
VdbeCoverageIf(v, bRev!=0);
|
||||
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
|
||||
|
50
test/emptytable.test
Normal file
50
test/emptytable.test
Normal file
@ -0,0 +1,50 @@
|
||||
# 2017-02-15
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Test cases to show that a join involving an empty table is very fast.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# Build some test data
|
||||
#
|
||||
do_execsql_test emptytable-100 {
|
||||
CREATE TABLE t1(a);
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
|
||||
INSERT INTO t1(a) SELECT x FROM c;
|
||||
CREATE TABLE empty(x);
|
||||
SELECT count(*) FROM t1;
|
||||
} {100}
|
||||
|
||||
# Interrupt queries after 1M cycles to prevent burning excess CPU
|
||||
proc stopDb {args} {
|
||||
db interrupt
|
||||
}
|
||||
db progress 1000000 {stopDb}
|
||||
|
||||
# Prior to the query planner optimization on 2017-02-15, this query would
|
||||
# take a ridiculous amount of time. If that optimization stops working,
|
||||
# the result here will be in interrupt for running too long.
|
||||
#
|
||||
do_catchsql_test emptytable-110 {
|
||||
SELECT count(*) FROM t1, t1, t1, t1, t1, t1, empty;
|
||||
} {0 0}
|
||||
|
||||
do_catchsql_test emptytable-120 {
|
||||
SELECT count(*) FROM t1, t1 LEFT JOIN empty;
|
||||
} {0 10000}
|
||||
do_catchsql_test emptytable-121 {
|
||||
SELECT count(*) FROM t1, t1 LEFT JOIN t1, empty;
|
||||
} {0 0}
|
||||
|
||||
|
||||
finish_test
|
Reference in New Issue
Block a user