1*4c68e6d2Sdrh# 2007 October 23 2*4c68e6d2Sdrh# 3*4c68e6d2Sdrh# The author disclaims copyright to this source code. In place of 4*4c68e6d2Sdrh# a legal notice, here is a blessing: 5*4c68e6d2Sdrh# 6*4c68e6d2Sdrh# May you do good and not evil. 7*4c68e6d2Sdrh# May you find forgiveness for yourself and forgive others. 8*4c68e6d2Sdrh# May you share freely, never taking more than you give. 9*4c68e6d2Sdrh# 10*4c68e6d2Sdrh#************************************************************************* 11*4c68e6d2Sdrh# This file implements regression tests for SQLite library. The 12*4c68e6d2Sdrh# focus of this script is measuring executing speed. More specifically, 13*4c68e6d2Sdrh# the focus is on the speed of: 14*4c68e6d2Sdrh# 15*4c68e6d2Sdrh# * joins 16*4c68e6d2Sdrh# * views 17*4c68e6d2Sdrh# * sub-selects 18*4c68e6d2Sdrh# * triggers 19*4c68e6d2Sdrh# 20*4c68e6d2Sdrh# $Id: speed4p.explain,v 1.1 2008/04/16 12:57:48 drh Exp $ 21*4c68e6d2Sdrh# 22*4c68e6d2Sdrh 23*4c68e6d2Sdrhset testdir [file dirname $argv0] 24*4c68e6d2Sdrhsource $testdir/tester.tcl 25*4c68e6d2Sdrhspeed_trial_init speed1 26*4c68e6d2Sdrh 27*4c68e6d2Sdrh# Set a uniform random seed 28*4c68e6d2Sdrhexpr srand(0) 29*4c68e6d2Sdrh 30*4c68e6d2Sdrhset sqlout [open speed1.txt w] 31*4c68e6d2Sdrhproc tracesql {sql} { 32*4c68e6d2Sdrh puts $::sqlout $sql\; 33*4c68e6d2Sdrh} 34*4c68e6d2Sdrh#db trace tracesql 35*4c68e6d2Sdrh 36*4c68e6d2Sdrh# The number_name procedure below converts its argment (an integer) 37*4c68e6d2Sdrh# into a string which is the English-language name for that number. 38*4c68e6d2Sdrh# 39*4c68e6d2Sdrh# Example: 40*4c68e6d2Sdrh# 41*4c68e6d2Sdrh# puts [number_name 123] -> "one hundred twenty three" 42*4c68e6d2Sdrh# 43*4c68e6d2Sdrhset ones {zero one two three four five six seven eight nine 44*4c68e6d2Sdrh ten eleven twelve thirteen fourteen fifteen sixteen seventeen 45*4c68e6d2Sdrh eighteen nineteen} 46*4c68e6d2Sdrhset tens {{} ten twenty thirty forty fifty sixty seventy eighty ninety} 47*4c68e6d2Sdrhproc number_name {n} { 48*4c68e6d2Sdrh if {$n>=1000} { 49*4c68e6d2Sdrh set txt "[number_name [expr {$n/1000}]] thousand" 50*4c68e6d2Sdrh set n [expr {$n%1000}] 51*4c68e6d2Sdrh } else { 52*4c68e6d2Sdrh set txt {} 53*4c68e6d2Sdrh } 54*4c68e6d2Sdrh if {$n>=100} { 55*4c68e6d2Sdrh append txt " [lindex $::ones [expr {$n/100}]] hundred" 56*4c68e6d2Sdrh set n [expr {$n%100}] 57*4c68e6d2Sdrh } 58*4c68e6d2Sdrh if {$n>=20} { 59*4c68e6d2Sdrh append txt " [lindex $::tens [expr {$n/10}]]" 60*4c68e6d2Sdrh set n [expr {$n%10}] 61*4c68e6d2Sdrh } 62*4c68e6d2Sdrh if {$n>0} { 63*4c68e6d2Sdrh append txt " [lindex $::ones $n]" 64*4c68e6d2Sdrh } 65*4c68e6d2Sdrh set txt [string trim $txt] 66*4c68e6d2Sdrh if {$txt==""} {set txt zero} 67*4c68e6d2Sdrh return $txt 68*4c68e6d2Sdrh} 69*4c68e6d2Sdrh 70*4c68e6d2Sdrh# Summary of tests: 71*4c68e6d2Sdrh# 72*4c68e6d2Sdrh# speed4p-join1: Join three tables using IPK index. 73*4c68e6d2Sdrh# speed4p-join2: Join three tables using an index. 74*4c68e6d2Sdrh# speed4p-join3: Join two tables without an index. 75*4c68e6d2Sdrh# 76*4c68e6d2Sdrh# speed4p-view1: Querying a view. 77*4c68e6d2Sdrh# speed4p-table1: Same queries as in speed4p-view1, but run directly against 78*4c68e6d2Sdrh# the tables for comparison purposes. 79*4c68e6d2Sdrh# 80*4c68e6d2Sdrh# speed4p-subselect1: A SELECT statement that uses many sub-queries.. 81*4c68e6d2Sdrh# 82*4c68e6d2Sdrh# speed4p-trigger1: An INSERT statement that fires a trigger. 83*4c68e6d2Sdrh# speed4p-trigger2: An UPDATE statement that fires a trigger. 84*4c68e6d2Sdrh# speed4p-trigger3: A DELETE statement that fires a trigger. 85*4c68e6d2Sdrh# speed4p-notrigger1: Same operation as trigger1, but without the trigger. 86*4c68e6d2Sdrh# speed4p-notrigger2: " trigger2 " 87*4c68e6d2Sdrh# speed4p-notrigger3: " trigger3 " 88*4c68e6d2Sdrh# 89*4c68e6d2Sdrh 90*4c68e6d2Sdrh# Set up the schema. Each of the tables t1, t2 and t3 contain 50,000 rows. 91*4c68e6d2Sdrh# This creates a database of around 16MB. 92*4c68e6d2Sdrhexecsql { 93*4c68e6d2Sdrh PRAGMA page_size=1024; 94*4c68e6d2Sdrh PRAGMA cache_size=8192; 95*4c68e6d2Sdrh PRAGMA locking_mode=EXCLUSIVE; 96*4c68e6d2Sdrh BEGIN; 97*4c68e6d2Sdrh CREATE TABLE t1(rowid INTEGER PRIMARY KEY, i INTEGER, t TEXT); 98*4c68e6d2Sdrh CREATE TABLE t2(rowid INTEGER PRIMARY KEY, i INTEGER, t TEXT); 99*4c68e6d2Sdrh CREATE TABLE t3(rowid INTEGER PRIMARY KEY, i INTEGER, t TEXT); 100*4c68e6d2Sdrh 101*4c68e6d2Sdrh CREATE VIEW v1 AS SELECT rowid, i, t FROM t1; 102*4c68e6d2Sdrh CREATE VIEW v2 AS SELECT rowid, i, t FROM t2; 103*4c68e6d2Sdrh CREATE VIEW v3 AS SELECT rowid, i, t FROM t3; 104*4c68e6d2Sdrh} 105*4c68e6d2Sdrhfor {set jj 1} {$jj <= 3} {incr jj} { 106*4c68e6d2Sdrh set stmt [string map "%T% t$jj" {INSERT INTO %T% VALUES(NULL, $i, $t)}] 107*4c68e6d2Sdrh for {set ii 0} {$ii < 50000} {incr ii} { 108*4c68e6d2Sdrh set i [expr {int(rand()*50000)}] 109*4c68e6d2Sdrh set t [number_name $i] 110*4c68e6d2Sdrh execsql $stmt 111*4c68e6d2Sdrh } 112*4c68e6d2Sdrh} 113*4c68e6d2Sdrhexecsql { 114*4c68e6d2Sdrh CREATE INDEX i1 ON t1(t); 115*4c68e6d2Sdrh CREATE INDEX i2 ON t2(t); 116*4c68e6d2Sdrh CREATE INDEX i3 ON t3(t); 117*4c68e6d2Sdrh COMMIT; 118*4c68e6d2Sdrh} 119*4c68e6d2Sdrh 120*4c68e6d2Sdrh# Before running these tests, disable the compiled statement cache built into 121*4c68e6d2Sdrh# the Tcl interface. This is because we want to test the speed of SQL 122*4c68e6d2Sdrh# compilation as well as execution. 123*4c68e6d2Sdrh# 124*4c68e6d2Sdrhdb cache size 0 125*4c68e6d2Sdrh 126*4c68e6d2Sdrh# Join t1, t2, t3 on IPK. 127*4c68e6d2Sdrhset sql "SELECT * FROM t1, t2, t3 WHERE t1.oid = t2.oid AND t2.oid = t3.oid" 128*4c68e6d2Sdrhexplain $sql 129*4c68e6d2Sdrhspeed_trial speed4p-join1 50000 row $sql 130*4c68e6d2Sdrh 131*4c68e6d2Sdrh# Join t1, t2, t3 on the non-IPK index. 132*4c68e6d2Sdrhset sql "SELECT * FROM t1, t2, t3 WHERE t1.t = t2.t AND t2.t = t3.t" 133*4c68e6d2Sdrhexplain $sql 134*4c68e6d2Sdrhspeed_trial speed4p-join2 50000 row $sql 135*4c68e6d2Sdrh 136*4c68e6d2Sdrh# Run 10000 simple queries against the views. 137*4c68e6d2Sdrhset script { 138*4c68e6d2Sdrh for {set ii 1} {$ii < 10000} {incr ii} { 139*4c68e6d2Sdrh set v [expr {$ii*3}] 140*4c68e6d2Sdrh set t [expr {$ii%3+1}] 141*4c68e6d2Sdrh db eval "SELECT * FROM v$t WHERE rowid = \$v" 142*4c68e6d2Sdrh } 143*4c68e6d2Sdrh} 144*4c68e6d2Sdrhexplain {SELECT * FROm v1 WHERE rowid=$v} 145*4c68e6d2Sdrhspeed_trial_tcl speed4p-view1 10000 stmt $script 146*4c68e6d2Sdrh 147*4c68e6d2Sdrh# Run the same 10000 simple queries as in the previous test case against 148*4c68e6d2Sdrh# the underlying tables. The compiled vdbe programs should be identical, so 149*4c68e6d2Sdrh# the only difference in running time is the extra time taken to compile 150*4c68e6d2Sdrh# the view definitions. 151*4c68e6d2Sdrh# 152*4c68e6d2Sdrhset script { 153*4c68e6d2Sdrh for {set ii 1} {$ii < 10000} {incr ii} { 154*4c68e6d2Sdrh set v [expr {$ii*3}] 155*4c68e6d2Sdrh set t [expr {$ii%3+1}] 156*4c68e6d2Sdrh db eval "SELECT t FROM t$t WHERE rowid = \$v" 157*4c68e6d2Sdrh } 158*4c68e6d2Sdrh} 159*4c68e6d2Sdrhexplain {SELECT * FROM t1 WHERE rowid=$v} 160*4c68e6d2Sdrhspeed_trial_tcl speed4p-table1 10000 stmt $script 161*4c68e6d2Sdrh 162*4c68e6d2Sdrh# Run a SELECT that uses sub-queries 10000 times. A total of 30000 sub-selects. 163*4c68e6d2Sdrh# 164*4c68e6d2Sdrhset script { 165*4c68e6d2Sdrh for {set ii 1} {$ii < 10000} {incr ii} { 166*4c68e6d2Sdrh set v [expr {$ii*3}] 167*4c68e6d2Sdrh db eval { 168*4c68e6d2Sdrh SELECT (SELECT t FROM t1 WHERE rowid = $v), 169*4c68e6d2Sdrh (SELECT t FROM t2 WHERE rowid = $v), 170*4c68e6d2Sdrh (SELECT t FROM t3 WHERE rowid = $v) 171*4c68e6d2Sdrh } 172*4c68e6d2Sdrh } 173*4c68e6d2Sdrh} 174*4c68e6d2Sdrhexplain { 175*4c68e6d2Sdrh SELECT (SELECT t FROM t1 WHERE rowid = $v), 176*4c68e6d2Sdrh (SELECT t FROM t2 WHERE rowid = $v), 177*4c68e6d2Sdrh (SELECT t FROM t3 WHERE rowid = $v) 178*4c68e6d2Sdrh} 179*4c68e6d2Sdrhspeed_trial_tcl speed4p-subselect1 10000 stmt $script 180*4c68e6d2Sdrh 181*4c68e6d2Sdrh# The following block tests the speed of some DML statements that cause 182*4c68e6d2Sdrh# triggers to fire. 183*4c68e6d2Sdrh# 184*4c68e6d2Sdrhexecsql { 185*4c68e6d2Sdrh CREATE TABLE log(op TEXT, r INTEGER, i INTEGER, t TEXT); 186*4c68e6d2Sdrh CREATE TABLE t4(rowid INTEGER PRIMARY KEY, i INTEGER, t TEXT); 187*4c68e6d2Sdrh CREATE TRIGGER t4_trigger1 AFTER INSERT ON t4 BEGIN 188*4c68e6d2Sdrh INSERT INTO log VALUES('INSERT INTO t4', new.rowid, new.i, new.t); 189*4c68e6d2Sdrh END; 190*4c68e6d2Sdrh CREATE TRIGGER t4_trigger2 AFTER UPDATE ON t4 BEGIN 191*4c68e6d2Sdrh INSERT INTO log VALUES('UPDATE OF t4', new.rowid, new.i, new.t); 192*4c68e6d2Sdrh END; 193*4c68e6d2Sdrh CREATE TRIGGER t4_trigger3 AFTER DELETE ON t4 BEGIN 194*4c68e6d2Sdrh INSERT INTO log VALUES('DELETE OF t4', old.rowid, old.i, old.t); 195*4c68e6d2Sdrh END; 196*4c68e6d2Sdrh BEGIN; 197*4c68e6d2Sdrh} 198*4c68e6d2Sdrhset list {} 199*4c68e6d2Sdrhfor {set ii 1} {$ii < 10000} {incr ii} { 200*4c68e6d2Sdrh lappend list $ii [number_name $ii] 201*4c68e6d2Sdrh} 202*4c68e6d2Sdrhset script { 203*4c68e6d2Sdrh foreach {ii name} $::list { 204*4c68e6d2Sdrh db eval {INSERT INTO t4 VALUES(NULL, $ii, $name)} 205*4c68e6d2Sdrh } 206*4c68e6d2Sdrh} 207*4c68e6d2Sdrhexplain {INSERT INTO t4 VALUES(NULL, $ii, $name)} 208*4c68e6d2Sdrhspeed_trial_tcl speed4p-trigger1 10000 stmt $script 209*4c68e6d2Sdrh 210*4c68e6d2Sdrhset list {} 211*4c68e6d2Sdrhfor {set ii 1} {$ii < 20000} {incr ii 2} { 212*4c68e6d2Sdrh set ii2 [expr {$ii*2}] 213*4c68e6d2Sdrh lappend list $ii $ii2 [number_name $ii2] 214*4c68e6d2Sdrh} 215*4c68e6d2Sdrhset script { 216*4c68e6d2Sdrh foreach {ii ii2 name} $::list { 217*4c68e6d2Sdrh db eval { 218*4c68e6d2Sdrh UPDATE t4 SET i = $ii2, t = $name WHERE rowid = $ii; 219*4c68e6d2Sdrh } 220*4c68e6d2Sdrh } 221*4c68e6d2Sdrh} 222*4c68e6d2Sdrhexplain {UPDATE t4 SET i = $ii2, t = $name WHERE rowid = $ii} 223*4c68e6d2Sdrhspeed_trial_tcl speed4p-trigger2 10000 stmt $script 224*4c68e6d2Sdrh 225*4c68e6d2Sdrhset script { 226*4c68e6d2Sdrh for {set ii 1} {$ii < 20000} {incr ii 2} { 227*4c68e6d2Sdrh db eval {DELETE FROM t4 WHERE rowid = $ii} 228*4c68e6d2Sdrh } 229*4c68e6d2Sdrh} 230*4c68e6d2Sdrhexplain {DELETE FROM t4 WHERE rowid = $ii} 231*4c68e6d2Sdrhspeed_trial_tcl speed4p-trigger3 10000 stmt $script 232*4c68e6d2Sdrhexecsql {COMMIT} 233*4c68e6d2Sdrh 234*4c68e6d2Sdrh# The following block contains the same tests as the above block that 235*4c68e6d2Sdrh# tests triggers, with one crucial difference: no triggers are defined. 236*4c68e6d2Sdrh# So the difference in speed between these tests and the preceding ones 237*4c68e6d2Sdrh# is the amount of time taken to compile and execute the trigger programs. 238*4c68e6d2Sdrh# 239*4c68e6d2Sdrhexecsql { 240*4c68e6d2Sdrh DROP TABLE t4; 241*4c68e6d2Sdrh DROP TABLE log; 242*4c68e6d2Sdrh VACUUM; 243*4c68e6d2Sdrh CREATE TABLE t4(rowid INTEGER PRIMARY KEY, i INTEGER, t TEXT); 244*4c68e6d2Sdrh BEGIN; 245*4c68e6d2Sdrh} 246*4c68e6d2Sdrhset list {} 247*4c68e6d2Sdrhfor {set ii 1} {$ii < 10000} {incr ii} { 248*4c68e6d2Sdrh lappend list $ii [number_name $ii] 249*4c68e6d2Sdrh} 250*4c68e6d2Sdrhset script { 251*4c68e6d2Sdrh foreach {ii name} $::list { 252*4c68e6d2Sdrh db eval {INSERT INTO t4 VALUES(NULL, $ii, $name);} 253*4c68e6d2Sdrh } 254*4c68e6d2Sdrh} 255*4c68e6d2Sdrhexplain {INSERT INTO t4 VALUES(NULL, $ii, $name)} 256*4c68e6d2Sdrhspeed_trial_tcl speed4p-notrigger1 10000 stmt $script 257*4c68e6d2Sdrh 258*4c68e6d2Sdrhset list {} 259*4c68e6d2Sdrhfor {set ii 1} {$ii < 20000} {incr ii 2} { 260*4c68e6d2Sdrh set ii2 [expr {$ii*2}] 261*4c68e6d2Sdrh lappend list $ii $ii2 [number_name $ii2] 262*4c68e6d2Sdrh} 263*4c68e6d2Sdrhset script { 264*4c68e6d2Sdrh foreach {ii ii2 name} $::list { 265*4c68e6d2Sdrh db eval { 266*4c68e6d2Sdrh UPDATE t4 SET i = $ii2, t = $name WHERE rowid = $ii; 267*4c68e6d2Sdrh } 268*4c68e6d2Sdrh } 269*4c68e6d2Sdrh} 270*4c68e6d2Sdrhexplain {UPDATE t4 SET i = $ii2, t = $name WHERE rowid = $ii} 271*4c68e6d2Sdrhspeed_trial_tcl speed4p-notrigger2 10000 stmt $script 272*4c68e6d2Sdrh 273*4c68e6d2Sdrhset script { 274*4c68e6d2Sdrh for {set ii 1} {$ii < 20000} {incr ii 2} { 275*4c68e6d2Sdrh db eval {DELETE FROM t4 WHERE rowid = $ii} 276*4c68e6d2Sdrh } 277*4c68e6d2Sdrh} 278*4c68e6d2Sdrhexplain {DELETE FROM t4 WHERE rowid = $ii} 279*4c68e6d2Sdrhspeed_trial_tcl speed4p-notrigger3 10000 stmt $script 280*4c68e6d2Sdrhexecsql {COMMIT} 281*4c68e6d2Sdrh 282*4c68e6d2Sdrhspeed_trial_summary speed4 283*4c68e6d2Sdrhfinish_test 284