mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +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.
|
C Query\splanner\soptimization\sto\sdetect\sempty\stables\sin\sa\sjoin\searly\sand\sbail\sout\nwithout\sdoing\sexcess\swork.
|
||||||
D 2017-02-15T18:30:57.375
|
D 2017-02-15T22:36:15.061
|
||||||
F Makefile.in edb6bcdd37748d2b1c3422ff727c748df7ffe918
|
F Makefile.in edb6bcdd37748d2b1c3422ff727c748df7ffe918
|
||||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||||
F Makefile.msc 067a6766f800cc8d72845ab61f8de4ffe8f3fc99
|
F Makefile.msc 067a6766f800cc8d72845ab61f8de4ffe8f3fc99
|
||||||
@ -477,7 +477,7 @@ F src/wal.h 06b2a0b599cc0f53ea97f497cf8c6b758c999f71
|
|||||||
F src/walker.c 91a6df7435827e41cff6bb7df50ea00934ee78b0
|
F src/walker.c 91a6df7435827e41cff6bb7df50ea00934ee78b0
|
||||||
F src/where.c 6397fab50fdbf9bde76c574ce07b3b776eb28b34
|
F src/where.c 6397fab50fdbf9bde76c574ce07b3b776eb28b34
|
||||||
F src/whereInt.h 2bcc3d176e6091cb8f50a30b65c006e88a73614d
|
F src/whereInt.h 2bcc3d176e6091cb8f50a30b65c006e88a73614d
|
||||||
F src/wherecode.c 99a8ced164c75edf41b3a865a75381c9adb38b28
|
F src/wherecode.c 677e95413c472c0b413023b6b69a47f40fce1b04
|
||||||
F src/whereexpr.c 130cdd1a43af71b19755270fb1224874cf55158c
|
F src/whereexpr.c 130cdd1a43af71b19755270fb1224874cf55158c
|
||||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||||
@ -676,6 +676,7 @@ F test/e_wal.test ae9a593207a77d711443ee69ffe081fda9243625
|
|||||||
F test/e_walauto.test 248af31e73c98df23476a22bdb815524c9dc3ba8
|
F test/e_walauto.test 248af31e73c98df23476a22bdb815524c9dc3ba8
|
||||||
F test/e_walckpt.test 28c371a6bb5e5fe7f31679c1df1763a19d19e8a0
|
F test/e_walckpt.test 28c371a6bb5e5fe7f31679c1df1763a19d19e8a0
|
||||||
F test/e_walhook.test 4c0613a0c76e7a9d5c4c211e1b4cbcc1143914df
|
F test/e_walhook.test 4c0613a0c76e7a9d5c4c211e1b4cbcc1143914df
|
||||||
|
F test/emptytable.test a38110becbdfa6325cd65cb588dca658cd885f62
|
||||||
F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
|
F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
|
||||||
F test/enc2.test 83437a79ba1545a55fb549309175c683fb334473
|
F test/enc2.test 83437a79ba1545a55fb549309175c683fb334473
|
||||||
F test/enc3.test 6807f7a7740a00361ca8d0ccd66bc60c8dc5f2b6
|
F test/enc3.test 6807f7a7740a00361ca8d0ccd66bc60c8dc5f2b6
|
||||||
@ -1555,7 +1556,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P 810d29320b853b3a01aa50d8f2a0bceacf79e0aa
|
P 830b9235673be55f0c932fb157de03725e648c25
|
||||||
R 91fee55f54fe2e54254ba44f0240778d
|
R 32e948726be0c8ec843ec4b81e44685b
|
||||||
U mistachkin
|
U drh
|
||||||
Z 72fbc76e1b27f40edc76050b0de83496
|
Z 345aeb62ab5f52d0700dc3107ec5c535
|
||||||
|
@ -1 +1 @@
|
|||||||
830b9235673be55f0c932fb157de03725e648c25
|
58797e9bafa95709e0f706a15f42f93b409e2db5
|
@ -1062,6 +1062,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
|||||||
Vdbe *v; /* The prepared stmt under constructions */
|
Vdbe *v; /* The prepared stmt under constructions */
|
||||||
struct SrcList_item *pTabItem; /* FROM clause term being coded */
|
struct SrcList_item *pTabItem; /* FROM clause term being coded */
|
||||||
int addrBrk; /* Jump here to break out of the loop */
|
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 addrCont; /* Jump here to continue with next cycle */
|
||||||
int iRowidReg = 0; /* Rowid is stored in this register, if not zero */
|
int iRowidReg = 0; /* Rowid is stored in this register, if not zero */
|
||||||
int iReleaseReg = 0; /* Temp register to free before returning */
|
int iReleaseReg = 0; /* Temp register to free before returning */
|
||||||
@ -1103,6 +1104,11 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
|||||||
VdbeComment((v, "init LEFT JOIN no-match flag"));
|
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 */
|
/* Special case of a FROM clause subquery implemented as a co-routine */
|
||||||
if( pTabItem->fg.viaCoroutine ){
|
if( pTabItem->fg.viaCoroutine ){
|
||||||
int regYield = pTabItem->regReturn;
|
int regYield = pTabItem->regReturn;
|
||||||
@ -1287,7 +1293,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
|||||||
sqlite3ExprCacheAffinityChange(pParse, r1, 1);
|
sqlite3ExprCacheAffinityChange(pParse, r1, 1);
|
||||||
sqlite3ReleaseTempReg(pParse, rTemp);
|
sqlite3ReleaseTempReg(pParse, rTemp);
|
||||||
}else{
|
}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);
|
||||||
VdbeCoverageIf(v, bRev!=0);
|
VdbeCoverageIf(v, bRev!=0);
|
||||||
}
|
}
|
||||||
@ -1933,7 +1939,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
|||||||
codeCursorHint(pTabItem, pWInfo, pLevel, 0);
|
codeCursorHint(pTabItem, pWInfo, pLevel, 0);
|
||||||
pLevel->op = aStep[bRev];
|
pLevel->op = aStep[bRev];
|
||||||
pLevel->p1 = iCur;
|
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);
|
||||||
VdbeCoverageIf(v, bRev!=0);
|
VdbeCoverageIf(v, bRev!=0);
|
||||||
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
|
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