1# 2006 November 23 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 measuring executing speed. 13# 14# $Id: speed2.test,v 1.3 2007/03/27 12:04:06 drh Exp $ 15# 16 17set testdir [file dirname $argv0] 18source $testdir/tester.tcl 19 20# Set a uniform random seed 21expr srand(0) 22 23set sqlout [open speed2.txt w] 24proc tracesql {sql} { 25 puts $::sqlout $sql\; 26} 27#db trace tracesql 28 29# The number_name procedure below converts its argment (an integer) 30# into a string which is the English-language name for that number. 31# 32# Example: 33# 34# puts [number_name 123] -> "one hundred twenty three" 35# 36set ones {zero one two three four five six seven eight nine 37 ten eleven twelve thirteen fourteen fifteen sixteen seventeen 38 eighteen nineteen} 39set tens {{} ten twenty thirty forty fifty sixty seventy eighty ninety} 40proc number_name {n} { 41 if {$n>=1000} { 42 set txt "[number_name [expr {$n/1000}]] thousand" 43 set n [expr {$n%1000}] 44 } else { 45 set txt {} 46 } 47 if {$n>=100} { 48 append txt " [lindex $::ones [expr {$n/100}]] hundred" 49 set n [expr {$n%100}] 50 } 51 if {$n>=20} { 52 append txt " [lindex $::tens [expr {$n/10}]]" 53 set n [expr {$n%10}] 54 } 55 if {$n>0} { 56 append txt " [lindex $::ones $n]" 57 } 58 set txt [string trim $txt] 59 if {$txt==""} {set txt zero} 60 return $txt 61} 62 63# Create a database schema. 64# 65do_test speed2-1.0 { 66 execsql { 67 PRAGMA page_size=1024; 68 PRAGMA cache_size=8192; 69 PRAGMA locking_mode=EXCLUSIVE; 70 CREATE TABLE t1(a INTEGER, b INTEGER, c TEXT); 71 CREATE TABLE t2(a INTEGER, b INTEGER, c TEXT); 72 CREATE INDEX i2a ON t2(a); 73 CREATE INDEX i2b ON t2(b); 74 } 75 execsql { 76 SELECT name FROM sqlite_master ORDER BY 1; 77 } 78} {i2a i2b t1 t2} 79 80 81# 50000 INSERTs on an unindexed table 82# 83set sql {} 84for {set i 1} {$i<=50000} {incr i} { 85 set r [expr {int(rand()*500000)}] 86 append sql "INSERT INTO t1 VALUES($i,$r,'[number_name $r]');\n" 87} 88db eval BEGIN 89speed_trial speed2-insert1 50000 row $sql 90db eval COMMIT 91 92# 50000 INSERTs on an indexed table 93# 94set sql {} 95for {set i 1} {$i<=50000} {incr i} { 96 set r [expr {int(rand()*500000)}] 97 append sql "INSERT INTO t2 VALUES($i,$r,'[number_name $r]');\n" 98} 99db eval BEGIN 100speed_trial speed2-insert2 50000 row $sql 101db eval COMMIT 102 103 104 105# 50 SELECTs on an integer comparison. There is no index so 106# a full table scan is required. 107# 108set sql {} 109for {set i 0} {$i<50} {incr i} { 110 set lwr [expr {$i*100}] 111 set upr [expr {($i+10)*100}] 112 append sql "SELECT count(*), avg(b) FROM t1 WHERE b>=$lwr AND b<$upr;" 113} 114speed_trial speed2-select1 [expr {50*50000}] row $sql 115 116# 50 SELECTs on an LIKE comparison. There is no index so a full 117# table scan is required. 118# 119set sql {} 120for {set i 0} {$i<50} {incr i} { 121 append sql \ 122 "SELECT count(*), avg(b) FROM t1 WHERE c LIKE '%[number_name $i]%';" 123} 124speed_trial speed2-select2 [expr {50*50000}] row $sql 125 126# Create indices 127# 128db eval BEGIN 129speed_trial speed2-createidx 150000 row { 130 CREATE INDEX i1a ON t1(a); 131 CREATE INDEX i1b ON t1(b); 132 CREATE INDEX i1c ON t1(c); 133} 134db eval COMMIT 135 136# 5000 SELECTs on an integer comparison where the integer is 137# indexed. 138# 139set sql {} 140for {set i 0} {$i<5000} {incr i} { 141 set lwr [expr {$i*100}] 142 set upr [expr {($i+10)*100}] 143 append sql "SELECT count(*), avg(b) FROM t1 WHERE b>=$lwr AND b<$upr;" 144} 145speed_trial speed2-select3 5000 stmt $sql 146 147# 100000 random SELECTs against rowid. 148# 149set sql {} 150for {set i 1} {$i<=100000} {incr i} { 151 set id [expr {int(rand()*50000)+1}] 152 append sql "SELECT c=='hi' FROM t1 WHERE rowid=$id;\n" 153} 154speed_trial speed2-select4 100000 row $sql 155 156# 100000 random SELECTs against a unique indexed column. 157# 158set sql {} 159for {set i 1} {$i<=100000} {incr i} { 160 set id [expr {int(rand()*50000)+1}] 161 append sql "SELECT c FROM t1 WHERE a=$id;" 162} 163speed_trial speed2-select5 100000 row $sql 164 165# 50000 random SELECTs against an indexed column text column 166# 167set sql {} 168db eval {SELECT c FROM t1 ORDER BY random() LIMIT 50000} { 169 append sql "SELECT c FROM t1 WHERE c='$c';" 170} 171speed_trial speed2-select6 50000 row $sql 172 173# Vacuum 174speed_trial speed2-vacuum 100000 row VACUUM 175 176# 5000 updates of ranges where the field being compared is indexed. 177# 178set sql {} 179for {set i 0} {$i<5000} {incr i} { 180 set lwr [expr {$i*2}] 181 set upr [expr {($i+1)*2}] 182 append sql "UPDATE t1 SET b=b*2 WHERE a>=$lwr AND a<$upr;" 183} 184db eval BEGIN 185speed_trial speed2-update1 5000 stmt $sql 186db eval COMMIT 187 188# 50000 single-row updates. An index is used to find the row quickly. 189# 190set sql {} 191for {set i 0} {$i<50000} {incr i} { 192 set r [expr {int(rand()*500000)}] 193 append sql "UPDATE t1 SET b=$r WHERE a=$i;" 194} 195db eval BEGIN 196speed_trial speed2-update2 50000 row $sql 197db eval COMMIT 198 199# 1 big text update that touches every row in the table. 200# 201speed_trial speed2-update3 50000 row { 202 UPDATE t1 SET c=a; 203} 204 205# Many individual text updates. Each row in the table is 206# touched through an index. 207# 208set sql {} 209for {set i 1} {$i<=50000} {incr i} { 210 set r [expr {int(rand()*500000)}] 211 append sql "UPDATE t1 SET c='[number_name $r]' WHERE a=$i;" 212} 213db eval BEGIN 214speed_trial speed2-update4 50000 row $sql 215db eval COMMIT 216 217# Delete all content in a table. 218# 219speed_trial speed2-delete1 50000 row {DELETE FROM t1} 220 221# Copy one table into another 222# 223speed_trial speed2-copy1 50000 row {INSERT INTO t1 SELECT * FROM t2} 224 225# Delete all content in a table, one row at a time. 226# 227speed_trial speed2-delete2 50000 row {DELETE FROM t1 WHERE 1} 228 229# Refill the table yet again 230# 231speed_trial speed2-copy2 50000 row {INSERT INTO t1 SELECT * FROM t2} 232 233# Drop the table and recreate it without its indices. 234# 235db eval BEGIN 236speed_trial speed2-drop1 50000 row { 237 DROP TABLE t1; 238 CREATE TABLE t1(a INTEGER, b INTEGER, c TEXT); 239} 240db eval COMMIT 241 242# Refill the table yet again. This copy should be faster because 243# there are no indices to deal with. 244# 245speed_trial speed2-copy3 50000 row {INSERT INTO t1 SELECT * FROM t2} 246 247# Select 20000 rows from the table at random. 248# 249speed_trial speed2-random1 50000 row { 250 SELECT rowid FROM t1 ORDER BY random() LIMIT 20000 251} 252 253# Delete 20000 random rows from the table. 254# 255speed_trial speed2-random-del1 20000 row { 256 DELETE FROM t1 WHERE rowid IN 257 (SELECT rowid FROM t1 ORDER BY random() LIMIT 20000) 258} 259do_test speed2-1.1 { 260 db one {SELECT count(*) FROM t1} 261} 30000 262 263 264# Delete 20000 more rows at random from the table. 265# 266speed_trial speed2-random-del2 20000 row { 267 DELETE FROM t1 WHERE rowid IN 268 (SELECT rowid FROM t1 ORDER BY random() LIMIT 20000) 269} 270do_test speed2-1.2 { 271 db one {SELECT count(*) FROM t1} 272} 10000 273 274finish_test 275