Home | History | Annotate | Download | only in test
      1 # 2010 April 07
      2 #
      3 # The author disclaims copyright to this source code.  In place of
      4 # a legal notice, here is a blessing:
      5 #
      6 #    May you do good and not evil.
      7 #    May you find forgiveness for yourself and forgive others.
      8 #    May you share freely, never taking more than you give.
      9 #
     10 #*************************************************************************
     11 # This file implements regression tests for SQLite library.  The
     12 # focus of this script is testing automatic index creation logic.
     13 #
     14 
     15 set testdir [file dirname $argv0]
     16 source $testdir/tester.tcl
     17 
     18 # If the library is not compiled with automatic index support then
     19 # skip all tests in this file.
     20 #
     21 ifcapable {!autoindex} {
     22   finish_test
     23   return
     24 }
     25 
     26 # With automatic index turned off, we do a full scan of the T2 table
     27 do_test autoindex1-100 {
     28   db eval {
     29     CREATE TABLE t1(a,b);
     30     INSERT INTO t1 VALUES(1,11);
     31     INSERT INTO t1 VALUES(2,22);
     32     INSERT INTO t1 SELECT a+2, b+22 FROM t1;
     33     INSERT INTO t1 SELECT a+4, b+44 FROM t1;
     34     CREATE TABLE t2(c,d);
     35     INSERT INTO t2 SELECT a, 900+b FROM t1;
     36   }
     37   db eval {
     38     PRAGMA automatic_index=OFF;
     39     SELECT b, d FROM t1 JOIN t2 ON a=c ORDER BY b;
     40   }
     41 } {11 911 22 922 33 933 44 944 55 955 66 966 77 977 88 988}
     42 do_test autoindex1-101 {
     43   db status step
     44 } {63}
     45 do_test autoindex1-102 {
     46   db status autoindex
     47 } {0}
     48 
     49 # With autoindex turned on, we build an index once and then use that index
     50 # to find T2 values.
     51 do_test autoindex1-110 {
     52   db eval {
     53     PRAGMA automatic_index=ON;
     54     SELECT b, d FROM t1 JOIN t2 ON a=c ORDER BY b;
     55   }
     56 } {11 911 22 922 33 933 44 944 55 955 66 966 77 977 88 988}
     57 do_test autoindex1-111 {
     58   db status step
     59 } {7}
     60 do_test autoindex1-112 {
     61   db status autoindex
     62 } {7}
     63 
     64 # The same test as above, but this time the T2 query is a subquery rather
     65 # than a join.
     66 do_test autoindex1-200 {
     67   db eval {
     68     PRAGMA automatic_index=OFF;
     69     SELECT b, (SELECT d FROM t2 WHERE c=a) FROM t1;
     70   }
     71 } {11 911 22 922 33 933 44 944 55 955 66 966 77 977 88 988}
     72 do_test autoindex1-201 {
     73   db status step
     74 } {35}
     75 do_test autoindex1-202 {
     76   db status autoindex
     77 } {0}
     78 do_test autoindex1-210 {
     79   db eval {
     80     PRAGMA automatic_index=ON;
     81     SELECT b, (SELECT d FROM t2 WHERE c=a) FROM t1;
     82   }
     83 } {11 911 22 922 33 933 44 944 55 955 66 966 77 977 88 988}
     84 do_test autoindex1-211 {
     85   db status step
     86 } {7}
     87 do_test autoindex1-212 {
     88   db status autoindex
     89 } {7}
     90 
     91 
     92 # Modify the second table of the join while the join is in progress
     93 #
     94 do_test autoindex1-300 {
     95   set r {}
     96   db eval {SELECT b, d FROM t1 JOIN t2 ON (c=a)} {
     97     lappend r $b $d
     98     db eval {UPDATE t2 SET d=d+1}
     99   }
    100   set r
    101 } {11 911 22 922 33 933 44 944 55 955 66 966 77 977 88 988}
    102 do_test autoindex1-310 {
    103   db eval {SELECT d FROM t2 ORDER BY d}
    104 } {919 930 941 952 963 974 985 996}
    105 
    106 # The next test does a 10-way join on unindexed tables.  Without
    107 # automatic indices, the join will take a long time to complete.
    108 # With automatic indices, it should only take about a second.
    109 #
    110 do_test autoindex1-400 {
    111   db eval {
    112     CREATE TABLE t4(a, b);
    113     INSERT INTO t4 VALUES(1,2);
    114     INSERT INTO t4 VALUES(2,3);
    115   }
    116   for {set n 2} {$n<4096} {set n [expr {$n+$n}]} {
    117     db eval {INSERT INTO t4 SELECT a+$n, b+$n FROM t4}
    118   }
    119   db eval {
    120     SELECT count(*) FROM t4;
    121   }
    122 } {4096}
    123 do_test autoindex1-401 {
    124   db eval {
    125     SELECT count(*)
    126       FROM t4 AS x1
    127       JOIN t4 AS x2 ON x2.a=x1.b
    128       JOIN t4 AS x3 ON x3.a=x2.b
    129       JOIN t4 AS x4 ON x4.a=x3.b
    130       JOIN t4 AS x5 ON x5.a=x4.b
    131       JOIN t4 AS x6 ON x6.a=x5.b
    132       JOIN t4 AS x7 ON x7.a=x6.b
    133       JOIN t4 AS x8 ON x8.a=x7.b
    134       JOIN t4 AS x9 ON x9.a=x8.b
    135       JOIN t4 AS x10 ON x10.a=x9.b;
    136   }
    137 } {4087}
    138 
    139 # Ticket [8011086c85c6c404014c947fcf3eb9f42b184a0d] from 2010-07-08
    140 # Make sure automatic indices are not created for the RHS of an IN expression
    141 # that is not a correlated subquery.
    142 #
    143 do_execsql_test autoindex1-500 {
    144   CREATE TABLE t501(a INTEGER PRIMARY KEY, b);
    145   CREATE TABLE t502(x INTEGER PRIMARY KEY, y);
    146   EXPLAIN QUERY PLAN
    147   SELECT b FROM t501
    148    WHERE t501.a IN (SELECT x FROM t502 WHERE y=?);
    149 } {
    150   0 0 0 {SEARCH TABLE t501 USING INTEGER PRIMARY KEY (rowid=?) (~25 rows)} 
    151   0 0 0 {EXECUTE LIST SUBQUERY 1} 
    152   1 0 0 {SCAN TABLE t502 (~100000 rows)}
    153 }
    154 do_execsql_test autoindex1-501 {
    155   EXPLAIN QUERY PLAN
    156   SELECT b FROM t501
    157    WHERE t501.a IN (SELECT x FROM t502 WHERE y=t501.b);
    158 } {
    159   0 0 0 {SCAN TABLE t501 (~500000 rows)} 
    160   0 0 0 {EXECUTE CORRELATED LIST SUBQUERY 1} 
    161   1 0 0 {SEARCH TABLE t502 USING AUTOMATIC COVERING INDEX (y=?) (~7 rows)}
    162 }
    163 do_execsql_test autoindex1-502 {
    164   EXPLAIN QUERY PLAN
    165   SELECT b FROM t501
    166    WHERE t501.a=123
    167      AND t501.a IN (SELECT x FROM t502 WHERE y=t501.b);
    168 } {
    169   0 0 0 {SEARCH TABLE t501 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)} 
    170   0 0 0 {EXECUTE CORRELATED LIST SUBQUERY 1} 
    171   1 0 0 {SCAN TABLE t502 (~100000 rows)}
    172 }
    173 
    174 
    175 # The following code checks a performance regression reported on the
    176 # mailing list on 2010-10-19.  The problem is that the nRowEst field
    177 # of ephermeral tables was not being initialized correctly and so no
    178 # automatic index was being created for the emphemeral table when it was
    179 # used as part of a join.
    180 #
    181 do_execsql_test autoindex1-600 {
    182   CREATE TABLE flock_owner(
    183     owner_rec_id INTEGER CONSTRAINT flock_owner_key PRIMARY KEY,
    184     flock_no VARCHAR(6) NOT NULL REFERENCES flock (flock_no),
    185     owner_person_id INTEGER NOT NULL REFERENCES person (person_id),
    186     owner_change_date TEXT, last_changed TEXT NOT NULL,
    187     CONSTRAINT fo_owner_date UNIQUE (flock_no, owner_change_date)
    188   );
    189   CREATE TABLE sheep (
    190     Sheep_No char(7) NOT NULL,
    191     Date_of_Birth char(8),
    192     Sort_DoB text,
    193     Flock_Book_Vol char(2),
    194     Breeder_No char(6),
    195     Breeder_Person integer,
    196     Originating_Flock char(6),
    197     Registering_Flock char(6),
    198     Tag_Prefix char(9),
    199     Tag_No char(15),
    200     Sort_Tag_No integer,
    201     Breeders_Temp_Tag char(15),
    202     Sex char(1),
    203     Sheep_Name char(32),
    204     Sire_No char(7),
    205     Dam_No char(7),
    206     Register_Code char(1),
    207     Colour char(48),
    208     Colour_Code char(2),
    209     Pattern_Code char(8),
    210     Horns char(1),
    211     Litter_Size char(1),
    212     Coeff_of_Inbreeding real,
    213     Date_of_Registration text,
    214     Date_Last_Changed text,
    215     UNIQUE(Sheep_No));
    216   CREATE INDEX fo_flock_no_index  
    217               ON flock_owner (flock_no);
    218   CREATE INDEX fo_owner_change_date_index  
    219               ON flock_owner (owner_change_date);
    220   CREATE INDEX fo_owner_person_id_index  
    221               ON flock_owner (owner_person_id);
    222   CREATE INDEX sheep_org_flock_index  
    223            ON sheep (originating_flock);
    224   CREATE INDEX sheep_reg_flock_index  
    225            ON sheep (registering_flock);
    226   EXPLAIN QUERY PLAN
    227   SELECT x.sheep_no, x.registering_flock, x.date_of_registration
    228    FROM sheep x LEFT JOIN
    229        (SELECT s.sheep_no, prev.flock_no, prev.owner_person_id,
    230        s.date_of_registration, prev.owner_change_date
    231        FROM sheep s JOIN flock_owner prev ON s.registering_flock =
    232    prev.flock_no
    233        AND (prev.owner_change_date <= s.date_of_registration || ' 00:00:00')
    234        WHERE NOT EXISTS
    235            (SELECT 'x' FROM flock_owner later
    236            WHERE prev.flock_no = later.flock_no
    237            AND later.owner_change_date > prev.owner_change_date
    238            AND later.owner_change_date <= s.date_of_registration||' 00:00:00')
    239        ) y ON x.sheep_no = y.sheep_no
    240    WHERE y.sheep_no IS NULL
    241    ORDER BY x.registering_flock;
    242 } {
    243   1 0 0 {SCAN TABLE sheep AS s (~1000000 rows)} 
    244   1 1 1 {SEARCH TABLE flock_owner AS prev USING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date<?) (~2 rows)} 
    245   1 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 2} 
    246   2 0 0 {SEARCH TABLE flock_owner AS later USING COVERING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date>? AND owner_change_date<?) (~1 rows)} 
    247   0 0 0 {SCAN TABLE sheep AS x USING INDEX sheep_reg_flock_index (~1000000 rows)} 
    248   0 1 1 {SEARCH SUBQUERY 1 AS y USING AUTOMATIC COVERING INDEX (sheep_no=?) (~8 rows)}
    249 }
    250 
    251 finish_test
    252