mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-05 15:55:57 +03:00
Preparing for the 2.4.0 release. (CVS 426)
FossilOrigin-Name: 9f5b241cb2fc89f66d3762b4b4978b8e114caf53
This commit is contained in:
28
manifest
28
manifest
@@ -1,9 +1,9 @@
|
|||||||
C Bug\sfix:\supdates\swithin\sa\stransaction\swould\sfail\sif\sthere\swas\sexisted\na\stemporary\stable.\s(CVS\s425)
|
C Preparing\sfor\sthe\s2.4.0\srelease.\s(CVS\s426)
|
||||||
D 2002-03-10T21:21:00
|
D 2002-03-11T02:06:13
|
||||||
F Makefile.in 50f1b3351df109b5774771350d8c1b8d3640130d
|
F Makefile.in 50f1b3351df109b5774771350d8c1b8d3640130d
|
||||||
F Makefile.template 89e373b2dad0321df00400fa968dc14b61a03296
|
F Makefile.template 89e373b2dad0321df00400fa968dc14b61a03296
|
||||||
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
|
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
|
||||||
F VERSION 4bed6a4fd03c5b6580757d22549c836e7cf6211a
|
F VERSION b4f17c505b8cd87aca34ebc2eb916ff0b4bc259d
|
||||||
F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d
|
F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d
|
||||||
F config.guess f38b1e93d1e0fa6f5a6913e9e7b12774b9232588
|
F config.guess f38b1e93d1e0fa6f5a6913e9e7b12774b9232588
|
||||||
F config.log 6a73d03433669b10a3f0c221198c3f26b9413914
|
F config.log 6a73d03433669b10a3f0c221198c3f26b9413914
|
||||||
@@ -29,7 +29,7 @@ F src/hash.c cc259475e358baaf299b00a2c7370f2b03dda892
|
|||||||
F src/hash.h dca065dda89d4575f3176e75e9a3dc0f4b4fb8b9
|
F src/hash.h dca065dda89d4575f3176e75e9a3dc0f4b4fb8b9
|
||||||
F src/insert.c 42bfd145efd428d7e5f200dd49ea0b816fc30d79
|
F src/insert.c 42bfd145efd428d7e5f200dd49ea0b816fc30d79
|
||||||
F src/main.c b21019084b93fe685a8a25217d01f6958584ae9b
|
F src/main.c b21019084b93fe685a8a25217d01f6958584ae9b
|
||||||
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
|
F src/md5.c b2b1a34fce66ceca97f4e0dabc20be8be7933c92
|
||||||
F src/os.c db969ecd1bcb4fef01b0b541b8b17401b0eb7ed2
|
F src/os.c db969ecd1bcb4fef01b0b541b8b17401b0eb7ed2
|
||||||
F src/os.h a17596ecc7f38a228b83ecdb661fb03ce44726d6
|
F src/os.h a17596ecc7f38a228b83ecdb661fb03ce44726d6
|
||||||
F src/pager.c f136f5ba82c896d500a10b6a2e5caea62abf716b
|
F src/pager.c f136f5ba82c896d500a10b6a2e5caea62abf716b
|
||||||
@@ -43,8 +43,8 @@ F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
|||||||
F src/sqlite.h.in 1dae50411aee9439860d7fbe315183c582d27197
|
F src/sqlite.h.in 1dae50411aee9439860d7fbe315183c582d27197
|
||||||
F src/sqliteInt.h 6f4a1bea4858089eb516f59562762965c6ef5cb8
|
F src/sqliteInt.h 6f4a1bea4858089eb516f59562762965c6ef5cb8
|
||||||
F src/table.c 203a09d5d0009eeeb1f670370d52b4ce163a3b52
|
F src/table.c 203a09d5d0009eeeb1f670370d52b4ce163a3b52
|
||||||
F src/tclsqlite.c b9cf346e95291cb4c4f1bf5ac1d77db6b8ad023d
|
F src/tclsqlite.c df847b71b28277f1cfa1ee1e3e51452ffe5a9a26
|
||||||
F src/test1.c 33efd350dca27c52c58c553c04fd3a6a51f13c1f
|
F src/test1.c d46ab7a82a9c16a3b1ee363cb4c0f98c5ff65743
|
||||||
F src/test2.c d410dbd8a90faa466c3ab694fa0aa57f5a773aa6
|
F src/test2.c d410dbd8a90faa466c3ab694fa0aa57f5a773aa6
|
||||||
F src/test3.c 4e52fff8b01f08bd202f7633feda5639b7ba2b5e
|
F src/test3.c 4e52fff8b01f08bd202f7633feda5639b7ba2b5e
|
||||||
F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f
|
F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f
|
||||||
@@ -96,7 +96,7 @@ F test/tableapi.test 51d0c209aa6b1158cb952ec917c656d4ce66e9e4
|
|||||||
F test/tclsqlite.test ca8dd89b02ab68bd4540163c24551756a69f6783
|
F test/tclsqlite.test ca8dd89b02ab68bd4540163c24551756a69f6783
|
||||||
F test/temptable.test 0e9934283259a5e637eec756a7eefd6964c0f79b
|
F test/temptable.test 0e9934283259a5e637eec756a7eefd6964c0f79b
|
||||||
F test/tester.tcl dc1b56bd628b487e4d75bfd1e7480b5ed8810ac6
|
F test/tester.tcl dc1b56bd628b487e4d75bfd1e7480b5ed8810ac6
|
||||||
F test/trans.test 9e49495c06b1c41f889bf4f0fb195a015b126de0
|
F test/trans.test ae0b9a82d5d34122c3a3108781eb8d078091ccee
|
||||||
F test/unique.test 07776624b82221a80c8b4138ce0dd8b0853bb3ea
|
F test/unique.test 07776624b82221a80c8b4138ce0dd8b0853bb3ea
|
||||||
F test/update.test 3cf1ca0565f678063c2dfa9a7948d2d66ae1a778
|
F test/update.test 3cf1ca0565f678063c2dfa9a7948d2d66ae1a778
|
||||||
F test/vacuum.test 059871b312eb910bbe49dafde1d01490cc2c6bbe
|
F test/vacuum.test 059871b312eb910bbe49dafde1d01490cc2c6bbe
|
||||||
@@ -115,22 +115,22 @@ F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf
|
|||||||
F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
|
F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
|
||||||
F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b
|
F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b
|
||||||
F www/c_interface.tcl 567cda531aac9d68a61ef02e26c6b202bd856db2
|
F www/c_interface.tcl 567cda531aac9d68a61ef02e26c6b202bd856db2
|
||||||
F www/changes.tcl b43d9e32ed7af9a93c5a9b7321abe2ee6a8f4ea9
|
F www/changes.tcl 6e2b0b5347bb38b2ad371fce2c486db616f0437b
|
||||||
F www/conflict.tcl 81dd21f9a679e60aae049e9dd8ab53d59570cda2
|
F www/conflict.tcl 81dd21f9a679e60aae049e9dd8ab53d59570cda2
|
||||||
F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060
|
F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060
|
||||||
F www/download.tcl a6d75b8b117cd33dcb090bef7e80d7556d28ebe0
|
F www/download.tcl a6d75b8b117cd33dcb090bef7e80d7556d28ebe0
|
||||||
F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
|
F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
|
||||||
F www/faq.tcl c6d1d6d69a9083734ee73d1b5ee4253ae8f10074
|
F www/faq.tcl c6d1d6d69a9083734ee73d1b5ee4253ae8f10074
|
||||||
F www/formatchng.tcl 5cffc0ebd00b3085c976a527eeeef70db4ccc7a7
|
F www/formatchng.tcl 2ce21ff30663fad6618198fe747ce675df577590
|
||||||
F www/index.tcl eacd99bcc3132d6e6b74a51422d415cc0bf7bfdf
|
F www/index.tcl eacd99bcc3132d6e6b74a51422d415cc0bf7bfdf
|
||||||
F www/lang.tcl db13f9a9c5ce7a400fa7ae021cd99dc6b05fd74a
|
F www/lang.tcl d589f9a39c925d81fa9198b9215b4fd56da4192b
|
||||||
F www/mingw.tcl f1c7c0a7f53387dd9bb4f8c7e8571b7561510ebc
|
F www/mingw.tcl f1c7c0a7f53387dd9bb4f8c7e8571b7561510ebc
|
||||||
F www/opcode.tcl bdec8ef9f100dbd87bbef8976c54b88e43fd8ccc
|
F www/opcode.tcl bdec8ef9f100dbd87bbef8976c54b88e43fd8ccc
|
||||||
F www/speed.tcl 83457b2bf6bb430900bd48ca3dd98264d9a916a5
|
F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f
|
||||||
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
|
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
|
||||||
F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49
|
F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49
|
||||||
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
||||||
P 145516c93b1a03231e7d84f7f799a39655d7aa99
|
P 02cc2d60b2a5ee50efdbd90df90810ba559a453f
|
||||||
R 6aa24ae4349921bb6f6914f243156bfe
|
R 7b12f4656109e08ea529f581aa14155c
|
||||||
U drh
|
U drh
|
||||||
Z 61ec9c5d0ba02401da95448b5e8eb2b6
|
Z f234e1ef2f8006b126be3e8559884083
|
||||||
|
@@ -1 +1 @@
|
|||||||
02cc2d60b2a5ee50efdbd90df90810ba559a453f
|
9f5b241cb2fc89f66d3762b4b4978b8e114caf53
|
33
src/md5.c
33
src/md5.c
@@ -30,6 +30,7 @@
|
|||||||
*/
|
*/
|
||||||
#include <tcl.h>
|
#include <tcl.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "sqlite.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If compiled on a machine that doesn't have a 32-bit integer,
|
* If compiled on a machine that doesn't have a 32-bit integer,
|
||||||
@@ -350,3 +351,35 @@ int Md5_Init(Tcl_Interp *interp){
|
|||||||
Tcl_CreateCommand(interp, "md5file", md5file_cmd, 0, 0);
|
Tcl_CreateCommand(interp, "md5file", md5file_cmd, 0, 0);
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** During testing, the special md5sum() aggregate function is available.
|
||||||
|
** inside SQLite. The following routines implement that function.
|
||||||
|
*/
|
||||||
|
static void md5step(sqlite_func *context, int argc, const char **argv){
|
||||||
|
MD5Context *p;
|
||||||
|
int i;
|
||||||
|
if( argc<1 ) return;
|
||||||
|
p = sqlite_aggregate_context(context, sizeof(*p));
|
||||||
|
if( p==0 ) return;
|
||||||
|
if( sqlite_aggregate_count(context)==1 ){
|
||||||
|
MD5Init(p);
|
||||||
|
}
|
||||||
|
for(i=0; i<argc; i++){
|
||||||
|
if( argv[i] ){
|
||||||
|
MD5Update(p, (unsigned char*)argv[i], strlen(argv[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void md5finalize(sqlite_func *context){
|
||||||
|
MD5Context *p;
|
||||||
|
unsigned char digest[16];
|
||||||
|
char zBuf[33];
|
||||||
|
p = sqlite_aggregate_context(context, sizeof(*p));
|
||||||
|
MD5Final(digest,p);
|
||||||
|
DigestToBase16(digest, zBuf);
|
||||||
|
sqlite_set_result_string(context, zBuf, strlen(zBuf));
|
||||||
|
}
|
||||||
|
void Md5_Register(sqlite *db){
|
||||||
|
sqlite_create_aggregate(db, "md5sum", -1, md5step, md5finalize, 0);
|
||||||
|
}
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** A TCL Interface to SQLite
|
** A TCL Interface to SQLite
|
||||||
**
|
**
|
||||||
** $Id: tclsqlite.c,v 1.29 2002/01/16 21:00:27 drh Exp $
|
** $Id: tclsqlite.c,v 1.30 2002/03/11 02:06:13 drh Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
|
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
|
||||||
|
|
||||||
@@ -531,6 +531,12 @@ static int DbMain(void *cd, Tcl_Interp *interp, int argc, char **argv){
|
|||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
Tcl_CreateObjCommand(interp, argv[1], DbObjCmd, (char*)p, DbDeleteCmd);
|
Tcl_CreateObjCommand(interp, argv[1], DbObjCmd, (char*)p, DbDeleteCmd);
|
||||||
|
#ifdef SQLITE_TEST
|
||||||
|
{
|
||||||
|
extern void Md5_Register(sqlite*);
|
||||||
|
Md5_Register(p->db);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
src/test1.c
20
src/test1.c
@@ -13,7 +13,7 @@
|
|||||||
** is not included in the SQLite library. It is used for automated
|
** is not included in the SQLite library. It is used for automated
|
||||||
** testing of the SQLite library.
|
** testing of the SQLite library.
|
||||||
**
|
**
|
||||||
** $Id: test1.c,v 1.6 2002/01/16 21:00:27 drh Exp $
|
** $Id: test1.c,v 1.7 2002/03/11 02:06:13 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "tcl.h"
|
#include "tcl.h"
|
||||||
@@ -324,6 +324,23 @@ static int sqlite_malloc_stat(
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Usage: sqlite_abort
|
||||||
|
**
|
||||||
|
** Shutdown the process immediately. This is not a clean shutdown.
|
||||||
|
** This command is used to test the recoverability of a database in
|
||||||
|
** the event of a program crash.
|
||||||
|
*/
|
||||||
|
static int sqlite_abort(
|
||||||
|
void *NotUsed,
|
||||||
|
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||||
|
int argc, /* Number of arguments */
|
||||||
|
char **argv /* Text of each argument */
|
||||||
|
){
|
||||||
|
assert( interp==0 ); /* This will always fail */
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Register commands with the TCL interpreter.
|
** Register commands with the TCL interpreter.
|
||||||
*/
|
*/
|
||||||
@@ -344,5 +361,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
|||||||
Tcl_CreateCommand(interp, "sqlite_malloc_fail", sqlite_malloc_fail, 0, 0);
|
Tcl_CreateCommand(interp, "sqlite_malloc_fail", sqlite_malloc_fail, 0, 0);
|
||||||
Tcl_CreateCommand(interp, "sqlite_malloc_stat", sqlite_malloc_stat, 0, 0);
|
Tcl_CreateCommand(interp, "sqlite_malloc_stat", sqlite_malloc_stat, 0, 0);
|
||||||
#endif
|
#endif
|
||||||
|
Tcl_CreateCommand(interp, "sqlite_abort", sqlite_abort, 0, 0);
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
}
|
}
|
||||||
|
134
test/trans.test
134
test/trans.test
@@ -11,7 +11,7 @@
|
|||||||
# This file implements regression tests for SQLite library. The
|
# This file implements regression tests for SQLite library. The
|
||||||
# focus of this script is database locks.
|
# focus of this script is database locks.
|
||||||
#
|
#
|
||||||
# $Id: trans.test,v 1.10 2002/01/10 14:31:49 drh Exp $
|
# $Id: trans.test,v 1.11 2002/03/11 02:06:14 drh Exp $
|
||||||
|
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
@@ -664,4 +664,136 @@ do_test trans-6.39 {
|
|||||||
}
|
}
|
||||||
} {1 -2 -3 4 -5 -6}
|
} {1 -2 -3 4 -5 -6}
|
||||||
|
|
||||||
|
# Test to make sure rollback restores the database back to its original
|
||||||
|
# state.
|
||||||
|
#
|
||||||
|
do_test trans-7.1 {
|
||||||
|
execsql {BEGIN}
|
||||||
|
for {set i 0} {$i<1000} {incr i} {
|
||||||
|
set r1 [expr {rand()}]
|
||||||
|
set r2 [expr {rand()}]
|
||||||
|
set r3 [expr {rand()}]
|
||||||
|
execsql "INSERT INTO t2 VALUES($r1,$r2,$r3)"
|
||||||
|
}
|
||||||
|
execsql {COMMIT}
|
||||||
|
set ::checksum [execsql {SELECT md5sum(x,y,z) FROM t2}]
|
||||||
|
set ::checksum2 [
|
||||||
|
execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
|
||||||
|
]
|
||||||
|
execsql {SELECT count(*) FROM t2}
|
||||||
|
} {1001}
|
||||||
|
do_test trans-7.2 {
|
||||||
|
execsql {SELECT md5sum(x,y,z) FROM t2}
|
||||||
|
} $checksum
|
||||||
|
do_test trans-7.2.1 {
|
||||||
|
execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
|
||||||
|
} $checksum2
|
||||||
|
do_test trans-7.3 {
|
||||||
|
execsql {
|
||||||
|
BEGIN;
|
||||||
|
DELETE FROM t2;
|
||||||
|
ROLLBACK;
|
||||||
|
SELECT md5sum(x,y,z) FROM t2;
|
||||||
|
}
|
||||||
|
} $checksum
|
||||||
|
do_test trans-7.4 {
|
||||||
|
execsql {
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t2 SELECT * FROM t2;
|
||||||
|
ROLLBACK;
|
||||||
|
SELECT md5sum(x,y,z) FROM t2;
|
||||||
|
}
|
||||||
|
} $checksum
|
||||||
|
do_test trans-7.5 {
|
||||||
|
execsql {
|
||||||
|
BEGIN;
|
||||||
|
DELETE FROM t2;
|
||||||
|
ROLLBACK;
|
||||||
|
SELECT md5sum(x,y,z) FROM t2;
|
||||||
|
}
|
||||||
|
} $checksum
|
||||||
|
do_test trans-7.6 {
|
||||||
|
execsql {
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t2 SELECT * FROM t2;
|
||||||
|
ROLLBACK;
|
||||||
|
SELECT md5sum(x,y,z) FROM t2;
|
||||||
|
}
|
||||||
|
} $checksum
|
||||||
|
do_test trans-7.7 {
|
||||||
|
execsql {
|
||||||
|
BEGIN;
|
||||||
|
CREATE TABLE t3 AS SELECT * FROM t2;
|
||||||
|
INSERT INTO t2 SELECT * FROM t3;
|
||||||
|
ROLLBACK;
|
||||||
|
SELECT md5sum(x,y,z) FROM t2;
|
||||||
|
}
|
||||||
|
} $checksum
|
||||||
|
do_test trans-7.8 {
|
||||||
|
execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
|
||||||
|
} $checksum2
|
||||||
|
do_test trans-7.9 {
|
||||||
|
execsql {
|
||||||
|
BEGIN;
|
||||||
|
CREATE TEMP TABLE t3 AS SELECT * FROM t2;
|
||||||
|
INSERT INTO t2 SELECT * FROM t3;
|
||||||
|
ROLLBACK;
|
||||||
|
SELECT md5sum(x,y,z) FROM t2;
|
||||||
|
}
|
||||||
|
} $checksum
|
||||||
|
do_test trans-7.10 {
|
||||||
|
execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
|
||||||
|
} $checksum2
|
||||||
|
do_test trans-7.11 {
|
||||||
|
execsql {
|
||||||
|
BEGIN;
|
||||||
|
CREATE TEMP TABLE t3 AS SELECT * FROM t2;
|
||||||
|
INSERT INTO t2 SELECT * FROM t3;
|
||||||
|
DROP INDEX i2x;
|
||||||
|
DROP INDEX i2y;
|
||||||
|
CREATE INDEX i3a ON t3(x);
|
||||||
|
ROLLBACK;
|
||||||
|
SELECT md5sum(x,y,z) FROM t2;
|
||||||
|
}
|
||||||
|
} $checksum
|
||||||
|
do_test trans-7.12 {
|
||||||
|
execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
|
||||||
|
} $checksum2
|
||||||
|
do_test trans-7.13 {
|
||||||
|
execsql {
|
||||||
|
BEGIN;
|
||||||
|
DROP TABLE t2;
|
||||||
|
ROLLBACK;
|
||||||
|
SELECT md5sum(x,y,z) FROM t2;
|
||||||
|
}
|
||||||
|
} $checksum
|
||||||
|
do_test trans-7.14 {
|
||||||
|
execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
|
||||||
|
} $checksum2
|
||||||
|
|
||||||
|
# Arrange for another process to begin modifying the database but abort
|
||||||
|
# and die in the middle of the modification. Then have this process read
|
||||||
|
# the database. This process should detect the journal file and roll it
|
||||||
|
# back. Verify that this happens correctly.
|
||||||
|
#
|
||||||
|
set fd [open test.tcl w]
|
||||||
|
puts $fd {
|
||||||
|
sqlite db test.db
|
||||||
|
db eval {
|
||||||
|
BEGIN;
|
||||||
|
CREATE TABLE t3 AS SELECT * FROM t2;
|
||||||
|
DELETE FROM t2;
|
||||||
|
}
|
||||||
|
sqlite_abort
|
||||||
|
}
|
||||||
|
close $fd
|
||||||
|
do_test trans-8.1 {
|
||||||
|
catch {exec [info nameofexec] test.tcl}
|
||||||
|
execsql {SELECT md5sum(x,y,z) FROM t2}
|
||||||
|
} $checksum
|
||||||
|
do_test trans-8.2 {
|
||||||
|
execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
|
||||||
|
} $checksum2
|
||||||
|
|
||||||
|
|
||||||
finish_test
|
finish_test
|
||||||
|
@@ -17,7 +17,7 @@ proc chng {date desc} {
|
|||||||
puts "<DD><P><UL>$desc</UL></P></DD>"
|
puts "<DD><P><UL>$desc</UL></P></DD>"
|
||||||
}
|
}
|
||||||
|
|
||||||
chng {2002 Mar * (2.4.0)} {
|
chng {2002 Mar 10 (2.4.0)} {
|
||||||
<li>Change the name of the sanity_check PRAGMA to <b>integrity_check</b>
|
<li>Change the name of the sanity_check PRAGMA to <b>integrity_check</b>
|
||||||
and make it available in all compiles.</li>
|
and make it available in all compiles.</li>
|
||||||
<li>SELECT min() or max() of an indexed column with no WHERE or GROUP BY
|
<li>SELECT min() or max() of an indexed column with no WHERE or GROUP BY
|
||||||
@@ -40,6 +40,8 @@ chng {2002 Mar * (2.4.0)} {
|
|||||||
about 2.5 times faster and large DELETEs about 5 times faster.</li>
|
about 2.5 times faster and large DELETEs about 5 times faster.</li>
|
||||||
<li>Made the CACHE_SIZE pragma persistent</li>
|
<li>Made the CACHE_SIZE pragma persistent</li>
|
||||||
<li>Added the SYNCHRONOUS pragma</li>
|
<li>Added the SYNCHRONOUS pragma</li>
|
||||||
|
<li>Fixed a bug that was causing updates to fail inside of transactions when
|
||||||
|
the database contained a temporary table.</li>
|
||||||
}
|
}
|
||||||
|
|
||||||
chng {2002 Feb 18 (2.3.3)} {
|
chng {2002 Feb 18 (2.3.3)} {
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# Run this Tcl script to generate the formatchng.html file.
|
# Run this Tcl script to generate the formatchng.html file.
|
||||||
#
|
#
|
||||||
set rcsid {$Id: formatchng.tcl,v 1.3 2002/03/04 02:26:17 drh Exp $ }
|
set rcsid {$Id: formatchng.tcl,v 1.4 2002/03/11 02:06:14 drh Exp $ }
|
||||||
|
|
||||||
puts {<html>
|
puts {<html>
|
||||||
<head>
|
<head>
|
||||||
@@ -93,7 +93,7 @@ occurred since version 1.0.0:
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td valign="top">2.3.3 to 2.4.0</td>
|
<td valign="top">2.3.3 to 2.4.0</td>
|
||||||
<td valign="top">2002-Mar-?</td>
|
<td valign="top">2002-Mar-10</td>
|
||||||
<td>Beginning with version 2.4.0, SQLite added support for views.
|
<td>Beginning with version 2.4.0, SQLite added support for views.
|
||||||
Information about views is stored in the SQLITE_MASTER table. If an older
|
Information about views is stored in the SQLITE_MASTER table. If an older
|
||||||
version of SQLite attempts to read a database that contains VIEW information
|
version of SQLite attempts to read a database that contains VIEW information
|
||||||
|
61
www/lang.tcl
61
www/lang.tcl
@@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# Run this Tcl script to generate the sqlite.html file.
|
# Run this Tcl script to generate the sqlite.html file.
|
||||||
#
|
#
|
||||||
set rcsid {$Id: lang.tcl,v 1.27 2002/03/04 02:26:17 drh Exp $}
|
set rcsid {$Id: lang.tcl,v 1.28 2002/03/11 02:06:14 drh Exp $}
|
||||||
|
|
||||||
puts {<html>
|
puts {<html>
|
||||||
<head>
|
<head>
|
||||||
@@ -817,13 +817,19 @@ with caution.</p>
|
|||||||
<p>The current implementation supports the following pragmas:</p>
|
<p>The current implementation supports the following pragmas:</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li><p><b>PRAGMA cache_size = </b><i>Number-of-pages</i><b>;</b></p>
|
<li><p><b>PRAGMA cache_size;
|
||||||
<p>Change the maximum number of database disk pages that SQLite
|
<br>PRAGMA cache_size = </b><i>Number-of-pages</i><b>;</b></p>
|
||||||
will hold in memory at once. Each page uses about 1.5K of RAM.
|
<p>Query or change the maximum number of database disk pages that SQLite
|
||||||
The default cache size is 100. If you are doing UPDATEs or DELETEs
|
will hold in memory at once. Each page uses about 1.5K of memory.
|
||||||
|
The default cache size is 2000. If you are doing UPDATEs or DELETEs
|
||||||
that change many rows of a database and you do not mind if SQLite
|
that change many rows of a database and you do not mind if SQLite
|
||||||
uses more memory, you can increase the cache size for a possible speed
|
uses more memory, you can increase the cache size for a possible speed
|
||||||
improvement.</p></li>
|
improvement.</p>
|
||||||
|
<p>When you change the cache size using the cache_size pragma, the
|
||||||
|
change only endures for the current session. The cache size reverts
|
||||||
|
to the default value when the database is closed and reopened. Use
|
||||||
|
the <b>default_cache_size</b> pragma to check the cache size permanently
|
||||||
|
</p></li>
|
||||||
|
|
||||||
<li><p><b>PRAGMA count_changes = ON;
|
<li><p><b>PRAGMA count_changes = ON;
|
||||||
<br>PRAGMA count_changes = OFF;</b></p>
|
<br>PRAGMA count_changes = OFF;</b></p>
|
||||||
@@ -831,6 +837,39 @@ with caution.</p>
|
|||||||
be invoked once for each DELETE, INSERT, or UPDATE operation. The
|
be invoked once for each DELETE, INSERT, or UPDATE operation. The
|
||||||
argument is the number of rows that were changed.</p>
|
argument is the number of rows that were changed.</p>
|
||||||
|
|
||||||
|
<li><p><b>PRAGMA default_cache_size;
|
||||||
|
<br>PRAGMA default_cache_size = </b><i>Number-of-pages</i><b>;</b></p>
|
||||||
|
<p>Query or change the maximum number of database disk pages that SQLite
|
||||||
|
will hold in memory at once. Each page uses about 1.5K of memory.
|
||||||
|
This pragma works like the <b>cache_size</b> pragma with the addition
|
||||||
|
feature that it changes the cache size persistently. With this pragma,
|
||||||
|
you can set the cache size once and that setting is retained and reused
|
||||||
|
everytime you reopen the database.</p></li>
|
||||||
|
|
||||||
|
<li><p><b>PRAGMA default_synchronous;
|
||||||
|
<br>PRAGMA default_synchronous = ON;
|
||||||
|
<br>PRAGMA default_synchronous = OFF;</b></p>
|
||||||
|
<p>Query or change the setting of the "synchronous" flag in
|
||||||
|
the database. When synchronous is on (the default), the SQLite database
|
||||||
|
engine will pause at critical moments to make sure that data has actually
|
||||||
|
be written to the disk surface. (In other words, it invokes the
|
||||||
|
equivalent of the <b>fsync()</b> system call.) In synchronous mode,
|
||||||
|
an SQLite database should be fully recoverable even if the operating
|
||||||
|
system crashes or power is interrupted unexpectedly. The penalty for
|
||||||
|
this assurance is that some database operations take longer because the
|
||||||
|
engine has to wait on the (relatively slow) disk drive. The alternative
|
||||||
|
is to turn synchronous off. With synchronous off, SQLite continues
|
||||||
|
processing as soon as it has handed data off to the operating system.
|
||||||
|
If the application running SQLite crashes, the data will be safe, but
|
||||||
|
the database could (in theory) become corrupted if the operating system
|
||||||
|
crashes or the computer suddenly loses power. On the other hand, some
|
||||||
|
operations are as much as 50 or more times faster with synchronous off.
|
||||||
|
</p>
|
||||||
|
<p>This pragma changes the synchronous mode persistently. Once changed,
|
||||||
|
the mode stays as set even if the database is closed and reopened. The
|
||||||
|
<b>synchronous</b> pragma does the same thing but only applies the setting
|
||||||
|
to the current session.</p>
|
||||||
|
|
||||||
<li><p><b>PRAGMA empty_result_callbacks = ON;
|
<li><p><b>PRAGMA empty_result_callbacks = ON;
|
||||||
<br>PRAGMA empty_result_callbacks = OFF;</b></p>
|
<br>PRAGMA empty_result_callbacks = OFF;</b></p>
|
||||||
<p>When on, the EMPTY_RESULT_CALLBACKS pragma causes the callback
|
<p>When on, the EMPTY_RESULT_CALLBACKS pragma causes the callback
|
||||||
@@ -873,6 +912,16 @@ with caution.</p>
|
|||||||
a description of all problems. If everything is in order, "ok" is
|
a description of all problems. If everything is in order, "ok" is
|
||||||
returned.</p>
|
returned.</p>
|
||||||
|
|
||||||
|
<li><p><b>PRAGMA synchronous;
|
||||||
|
<br>PRAGMA synchronous = ON;
|
||||||
|
<br>PRAGMA synchronous = OFF;</b></p>
|
||||||
|
<p>Query or change the setting of the "synchronous" flag in
|
||||||
|
the database for the duration of the current database connect.
|
||||||
|
The synchronous flag reverts to its default value when the database
|
||||||
|
is closed and reopened. For additional information on the synchronous
|
||||||
|
flag, see the description of the <b>default_synchronous</b> pragma.</p>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li><p><b>PRAGMA table_info(</b><i>table-name</i><b>);</b></p>
|
<li><p><b>PRAGMA table_info(</b><i>table-name</i><b>);</b></p>
|
||||||
<p>For each column in the named table, invoke the callback function
|
<p>For each column in the named table, invoke the callback function
|
||||||
once with information about that column, including the column name,
|
once with information about that column, including the column name,
|
||||||
|
473
www/speed.tcl
473
www/speed.tcl
@@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# Run this Tcl script to generate the speed.html file.
|
# Run this Tcl script to generate the speed.html file.
|
||||||
#
|
#
|
||||||
set rcsid {$Id: speed.tcl,v 1.5 2001/11/24 13:23:05 drh Exp $ }
|
set rcsid {$Id: speed.tcl,v 1.6 2002/03/11 02:06:14 drh Exp $ }
|
||||||
|
|
||||||
puts {<html>
|
puts {<html>
|
||||||
<head>
|
<head>
|
||||||
@@ -18,282 +18,365 @@ puts "<p align=center>
|
|||||||
puts {
|
puts {
|
||||||
<h2>Executive Summary</h2>
|
<h2>Executive Summary</h2>
|
||||||
|
|
||||||
<p>A series of tests are run to measure the relative performance of
|
<p>A series of tests were run to measure the relative performance of
|
||||||
SQLite version 1.0 and 2.0 and PostgreSQL version 6.4.
|
SQLite 2.4.0, PostgreSQL, and MySQL
|
||||||
The following are general
|
The following are general
|
||||||
conclusions drawn from these experiments:
|
conclusions drawn from these experiments:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li><p>
|
<li><p>
|
||||||
SQLite 2.0 is significantly faster than both SQLite 1.0 and PostgreSQL
|
SQLite 2.4.0 is significantly faster than PostgreSQL
|
||||||
for most common operations.
|
for most common operations.
|
||||||
SQLite 2.0 is over 4 times faster than PostgreSQL for simple
|
|
||||||
query operations and about 7 times faster for <b>INSERT</b> statements
|
|
||||||
within a transaction.
|
|
||||||
</p></li>
|
</p></li>
|
||||||
<li><p>
|
<li><p>
|
||||||
PostgreSQL performs better on complex queries, possibly due to having
|
The speed of SQLite 2.4.0 is similar to MySQL.
|
||||||
a more sophisticated query optimizer.
|
This is true in spite of the
|
||||||
</p></li>
|
fact that SQLite contains full transaction support whereas the
|
||||||
<li><p>
|
version of MySQL tested did not.
|
||||||
SQLite 2.0 is significantly slower than both SQLite 1.0 and PostgreSQL
|
|
||||||
on <b>DROP TABLE</b> statements and on doing lots of small <b>INSERT</b>
|
|
||||||
statements that are not grouped into a single transaction.
|
|
||||||
</p></li>
|
</p></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2>Test Environment</h2>
|
<h2>Test Environment</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The platform used for these tests is a 550MHz Athlon with 256MB or memory
|
The platform used for these tests is a 1.6GHz Athlon with 1GB or memory
|
||||||
and 33MHz IDE disk drives. The operating system is RedHat Linux 6.0 with
|
and an IDE disk drive. The operating system is RedHat Linux 7.2 with
|
||||||
various upgrades, including an upgrade to kernel version 2.2.18.
|
a stock kernel.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
PostgreSQL version 6.4.2 was used for these tests because that is what
|
The PostgreSQL and MySQL servers used were as delivered by default on
|
||||||
came pre-installed with RedHat 6.0. Newer version of PostgreSQL may give
|
RedHat 7.2. No effort was made to tune these engines. Note in particular
|
||||||
better performance.
|
the the default MySQL configuration on RedHat 7.2 does not support
|
||||||
|
transactions. Not having to support transactions gives MySQL a
|
||||||
|
big advantage, but SQLite is still able to hold its own on most
|
||||||
|
tests.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
SQLite version 1.0.32 was compiled with -O2 optimization and without
|
SQLite was compiled with -O6 optimization and with
|
||||||
the -DNDEBUG=1 switch. Setting the NDEBUG macro disables all "assert()"
|
the -DNDEBUG=1 switch which disables the many "assert()" statements
|
||||||
statements within the code, but SQLite version 1.0 does not have any
|
in the SQLite code. The -DNDEBUG=1 compiler option roughly doubles
|
||||||
expensive assert() statements so the difference in performance is
|
the speed of SQLite.
|
||||||
negligible.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
SQLite version 2.0-alpha-2 was compiled with -O2 optimization and
|
|
||||||
with the -DNDEBUG=1 compiler switch. Setting the NDEBUG macro is very
|
|
||||||
important in SQLite version 2.0. SQLite 2.0 contains some expensive
|
|
||||||
"assert()" statements in the inner loop of its processing. Setting
|
|
||||||
the NDEBUG macro makes SQLite 2.0 run nearly twice as fast.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
All tests are conducted on an otherwise quiescent machine.
|
All tests are conducted on an otherwise quiescent machine.
|
||||||
A simple shell script was used to generate and run all the tests.
|
A simple Tcl script was used to generate and run all the tests.
|
||||||
Each test reports three different times:
|
A copy of this Tcl script can be found in the SQLite source tree
|
||||||
|
in the file <b>tools/speedtest.tcl</b>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<ol>
|
The times reported on all tests represent wall-clock time
|
||||||
<li> "<b>Real</b>" or wall-clock time. </li>
|
in seconds. Two separate time values are reported for SQLite.
|
||||||
<li> "<b>User</b>" time, the time spent executing user-level code. </li>
|
The first value is for SQLite in its default configuration with
|
||||||
<li> "<b>Sys</b>" or system time, the time spent in the operating system. </li>
|
full disk synchronization turned on. With synchronization turned
|
||||||
</ol>
|
on, SQLite executes
|
||||||
|
an <b>fsync()</b> system call (or the equivalent) at key points
|
||||||
|
to make certain that critical data has
|
||||||
|
actually been written to the disk drive surface. Synchronization
|
||||||
|
is necessary to guarantee the integrity of the database if the
|
||||||
|
operating system crashes or the computer powers down unexpectedly
|
||||||
|
in the middle of a database update. The second time reported for SQLite is
|
||||||
|
when synchronization is turned off. With synchronization off,
|
||||||
|
SQLite is sometimes much faster, but there is a risk that an
|
||||||
|
operating system crash or an unexpected power failure could
|
||||||
|
damage the database. Generally speaking, the synchronous SQLite
|
||||||
|
times are for comparison against PostgreSQL (which is also
|
||||||
|
synchronous) and the asynchronous SQLite times are for
|
||||||
|
comparison against the asynchronous MySQL engine.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h2>Test 1: 1000 INSERTs</h2>
|
||||||
|
<blockquote>
|
||||||
|
CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100));<br>
|
||||||
|
INSERT INTO t1 VALUES(1,13153,'thirteen thousand one hundred fifty three');<br>
|
||||||
|
INSERT INTO t1 VALUES(2,75560,'seventy five thousand five hundred sixty');<br>
|
||||||
|
<i>... 995 lines omitted</i><br>
|
||||||
|
INSERT INTO t1 VALUES(998,66289,'sixty six thousand two hundred eighty nine');<br>
|
||||||
|
INSERT INTO t1 VALUES(999,24322,'twenty four thousand three hundred twenty two');<br>
|
||||||
|
INSERT INTO t1 VALUES(1000,94142,'ninety four thousand one hundred forty two');<br>
|
||||||
|
|
||||||
|
</blockquote><table border=0 cellpadding=0 cellspacing=0>
|
||||||
|
<tr><td>PostgreSQL:</td><td align="right"> 4.027</td></tr>
|
||||||
|
<tr><td>MySQL:</td><td align="right"> 0.113</td></tr>
|
||||||
|
<tr><td>SQLite 2.4:</td><td align="right"> 8.409</td></tr>
|
||||||
|
<tr><td>SQLite 2.4 (nosync):</td><td align="right"> 0.188</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p>SQLite must close and reopen the database file, and thus invalidate
|
||||||
|
its cache, for each SQL statement. In spite of this, the asynchronous
|
||||||
|
version of SQLite is still nearly as fast as MySQL. Notice how much slower
|
||||||
|
the synchronous version is, however. This is due to the necessity of
|
||||||
|
calling <b>fsync()</b> after each SQL statement.</p>
|
||||||
|
|
||||||
|
<h2>Test 2: 25000 INSERTs in a transaction</h2>
|
||||||
|
<blockquote>
|
||||||
|
BEGIN;<br>
|
||||||
|
CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100));<br>
|
||||||
|
INSERT INTO t2 VALUES(1,298361,'two hundred ninety eight thousand three hundred sixty one');<br>
|
||||||
|
<i>... 24997 lines omitted</i><br>
|
||||||
|
INSERT INTO t2 VALUES(24999,447847,'four hundred forty seven thousand eight hundred forty seven');<br>
|
||||||
|
INSERT INTO t2 VALUES(25000,473330,'four hundred seventy three thousand three hundred thirty');<br>
|
||||||
|
COMMIT;<br>
|
||||||
|
|
||||||
|
</blockquote><table border=0 cellpadding=0 cellspacing=0>
|
||||||
|
<tr><td>PostgreSQL:</td><td align="right"> 5.175</td></tr>
|
||||||
|
<tr><td>MySQL:</td><td align="right"> 2.444</td></tr>
|
||||||
|
<tr><td>SQLite 2.4:</td><td align="right"> 0.858</td></tr>
|
||||||
|
<tr><td>SQLite 2.4 (nosync):</td><td align="right"> 0.739</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
PostgreSQL uses a client-server model. The experiment is unable to measure
|
When all the INSERTs are put in a transaction, SQLite no longer has to
|
||||||
CPU used by the server, only the client, so the "user" and "sys" numbers
|
close and reopen the database between each statement. It also does not
|
||||||
from PostgreSQL are meaningless.
|
have to do any fsync()s until the very end. When unshackled in
|
||||||
|
this way, SQLite is much faster than either PostgreSQL and MySQL.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Test 1: CREATE TABLE</h2>
|
<h2>Test 3: 100 SELECTs without an index</h2>
|
||||||
|
<blockquote>
|
||||||
|
SELECT count(*), avg(b) FROM t2 WHERE b>=0 AND b<1000;<br>
|
||||||
|
SELECT count(*), avg(b) FROM t2 WHERE b>=100 AND b<1100;<br>
|
||||||
|
SELECT count(*), avg(b) FROM t2 WHERE b>=200 AND b<1200;<br>
|
||||||
|
<i>... 94 lines omitted</i><br>
|
||||||
|
SELECT count(*), avg(b) FROM t2 WHERE b>=9700 AND b<10700;<br>
|
||||||
|
SELECT count(*), avg(b) FROM t2 WHERE b>=9800 AND b<10800;<br>
|
||||||
|
SELECT count(*), avg(b) FROM t2 WHERE b>=9900 AND b<10900;<br>
|
||||||
|
|
||||||
<blockquote><pre>
|
</blockquote><table border=0 cellpadding=0 cellspacing=0>
|
||||||
CREATE TABLE t1(f1 int, f2 int, f3 int);
|
<tr><td>PostgreSQL:</td><td align="right"> 3.773</td></tr>
|
||||||
COPY t1 FROM '/home/drh/sqlite/bld/speeddata3.txt';
|
<tr><td>MySQL:</td><td align="right"> 3.023</td></tr>
|
||||||
|
<tr><td>SQLite 2.4:</td><td align="right"> 6.281</td></tr>
|
||||||
PostgreSQL: real 1.84
|
<tr><td>SQLite 2.4 (nosync):</td><td align="right"> 6.247</td></tr>
|
||||||
SQLite 1.0: real 3.29 user 0.64 sys 1.60
|
</table>
|
||||||
SQLite 2.0: real 0.77 user 0.51 sys 0.05
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The speeddata3.txt data file contains 30000 rows of data.
|
This test does 100 queries on a 25000 entry table without an index,
|
||||||
|
thus requiring a full table scan. SQLite is about half the speed of
|
||||||
|
PostgreSQL and MySQL. This is because SQLite stores all data as strings
|
||||||
|
and must therefore call <b>strtod()</b> 5 million times in the
|
||||||
|
course of evaluating the WHERE clauses. Both PostgreSQL and MySQL
|
||||||
|
store data as binary values where appropriate and can forego
|
||||||
|
this conversion effort.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Test 2: SELECT</h2>
|
|
||||||
|
|
||||||
<blockquote><pre>
|
<h2>Test 4: 100 SELECTs on a string comparison</h2>
|
||||||
SELECT max(f2), min(f3), count(*) FROM t1
|
<blockquote>
|
||||||
WHERE f3<10000 OR f1>=20000;
|
SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%one%';<br>
|
||||||
|
SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%two%';<br>
|
||||||
|
SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%three%';<br>
|
||||||
|
<i>... 94 lines omitted</i><br>
|
||||||
|
SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%ninety eight%';<br>
|
||||||
|
SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%ninety nine%';<br>
|
||||||
|
SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%one hundred%';<br>
|
||||||
|
|
||||||
PostgreSQL: real 1.22
|
</blockquote><table border=0 cellpadding=0 cellspacing=0>
|
||||||
SQLite 1.0: real 0.80 user 0.67 sys 0.12
|
<tr><td>PostgreSQL:</td><td align="right"> 16.726</td></tr>
|
||||||
SQLite 2.0: real 0.65 user 0.60 sys 0.05
|
<tr><td>MySQL:</td><td align="right"> 5.237</td></tr>
|
||||||
</pre></blockquote>
|
<tr><td>SQLite 2.4:</td><td align="right"> 6.137</td></tr>
|
||||||
|
<tr><td>SQLite 2.4 (nosync):</td><td align="right"> 6.112</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
With no indices, a complete scan of the table must be performed
|
This set of 100 queries uses string comparisons instead of
|
||||||
(all 30000 rows) in order to complete this query.
|
numerical comparisions. As a result, the speed of SQLite is
|
||||||
|
compariable to are better then PostgreSQL and MySQL.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Test 3: CREATE INDEX</h2>
|
<h2>Test 5: Creating an index</h2>
|
||||||
|
<blockquote>
|
||||||
<blockquote><pre>
|
CREATE INDEX i2a ON t2(a);<br>CREATE INDEX i2b ON t2(b);
|
||||||
CREATE INDEX idx1 ON t1(f1);
|
</blockquote><table border=0 cellpadding=0 cellspacing=0>
|
||||||
CREATE INDEX idx2 ON t1(f2,f3);
|
<tr><td>PostgreSQL:</td><td align="right"> 0.510</td></tr>
|
||||||
|
<tr><td>MySQL:</td><td align="right"> 0.352</td></tr>
|
||||||
PostgreSQL: real 2.24
|
<tr><td>SQLite 2.4:</td><td align="right"> 0.809</td></tr>
|
||||||
SQLite 1.0: real 5.37 user 1.22 sys 3.10
|
<tr><td>SQLite 2.4 (nosync):</td><td align="right"> 0.720</td></tr>
|
||||||
SQLite 2.0: real 3.71 user 2.31 sys 1.06
|
</table>
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
PostgreSQL is fastest at creating new indices.
|
SQLite is slower at creating new indices. But since creating
|
||||||
Note that SQLite 2.0 is faster than SQLite 1.0 but still
|
new indices is an uncommon operation, this is not seen as a
|
||||||
spends longer in user-space code.
|
problem.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Test 4: SELECT using an index</h2>
|
<h2>Test 6: 5000 SELECTs with an index</h2>
|
||||||
|
<blockquote>
|
||||||
|
SELECT count(*), avg(b) FROM t2 WHERE b>=0 AND b<100;<br>
|
||||||
|
SELECT count(*), avg(b) FROM t2 WHERE b>=100 AND b<200;<br>
|
||||||
|
SELECT count(*), avg(b) FROM t2 WHERE b>=200 AND b<300;<br>
|
||||||
|
<i>... 4994 lines omitted</i><br>
|
||||||
|
SELECT count(*), avg(b) FROM t2 WHERE b>=499700 AND b<499800;<br>
|
||||||
|
SELECT count(*), avg(b) FROM t2 WHERE b>=499800 AND b<499900;<br>
|
||||||
|
SELECT count(*), avg(b) FROM t2 WHERE b>=499900 AND b<500000;<br>
|
||||||
|
|
||||||
<blockquote><pre>
|
</blockquote><table border=0 cellpadding=0 cellspacing=0>
|
||||||
SELECT max(f2), min(f3), count(*) FROM t1
|
<tr><td>PostgreSQL:</td><td align="right"> 5.318</td></tr>
|
||||||
WHERE f3<10000 OR f1>=20000;
|
<tr><td>MySQL:</td><td align="right"> 1.555</td></tr>
|
||||||
|
<tr><td>SQLite 2.4:</td><td align="right"> 1.289</td></tr>
|
||||||
PostgreSQL: real 0.19
|
<tr><td>SQLite 2.4 (nosync):</td><td align="right"> 1.273</td></tr>
|
||||||
SQLite 1.0: real 0.77 user 0.66 sys 0.12
|
</table>
|
||||||
SQLite 2.0: real 0.62 user 0.62 sys 0.01
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
This is the same query as in Test 2, but now there are indices.
|
This test runs a set of 5000 queries that are similar in form to
|
||||||
Unfortunately, SQLite is reasonably simple-minded about its querying
|
those in test 3. But now instead of being half as fast, SQLite
|
||||||
and not able to take advantage of the indices. It still does a
|
is faster than both PostgreSQL and MySQL.
|
||||||
linear scan of the entire table. PostgreSQL, on the other hand,
|
|
||||||
is able to use the indices to make its query over six times faster.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Test 5: SELECT a single record</h2>
|
<h2>Test 7: 1000 UPDATEs without an index</h2>
|
||||||
|
<blockquote>
|
||||||
|
BEGIN;<br>
|
||||||
|
UPDATE t1 SET b=b*2 WHERE a>=0 AND a<10;<br>
|
||||||
|
UPDATE t1 SET b=b*2 WHERE a>=10 AND a<20;<br>
|
||||||
|
<i>... 996 lines omitted</i><br>
|
||||||
|
UPDATE t1 SET b=b*2 WHERE a>=9980 AND a<9990;<br>
|
||||||
|
UPDATE t1 SET b=b*2 WHERE a>=9990 AND a<10000;<br>
|
||||||
|
COMMIT;<br>
|
||||||
|
|
||||||
<blockquote><pre>
|
</blockquote><table border=0 cellpadding=0 cellspacing=0>
|
||||||
SELECT f2, f3 FROM t1 WHERE f1==1;
|
<tr><td>PostgreSQL:</td><td align="right"> 1.828</td></tr>
|
||||||
SELECT f2, f3 FROM t1 WHERE f1==2;
|
<tr><td>MySQL:</td><td align="right"> 9.272</td></tr>
|
||||||
SELECT f2, f3 FROM t1 WHERE f1==3;
|
<tr><td>SQLite 2.4:</td><td align="right"> 0.915</td></tr>
|
||||||
...
|
<tr><td>SQLite 2.4 (nosync):</td><td align="right"> 0.889</td></tr>
|
||||||
SELECT f2, f3 FROM t1 WHERE f1==998;
|
</table>
|
||||||
SELECT f2, f3 FROM t1 WHERE f1==999;
|
|
||||||
SELECT f2, f3 FROM t1 WHERE f1==1000;
|
|
||||||
|
|
||||||
PostgreSQL: real 0.95
|
|
||||||
SQLite 1.0: real 15.70 user 0.70 sys 14.41
|
|
||||||
SQLite 2.0: real 0.20 user 0.15 sys 0.05
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
This test involves 1000 separate SELECT statements, only the first
|
Here is a case where MySQL is over 10 times slower than SQLite.
|
||||||
and last three of which are show above. SQLite 2.0 is the clear
|
The reason for this is unclear.
|
||||||
winner. The miserable showing by SQLite 1.0 is due (it is thought)
|
|
||||||
to the high overhead of executing <b>gdbm_open</b> 2000 times in
|
|
||||||
quick succession.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Test 6: UPDATE</h2>
|
<h2>Test 8: 25000 UPDATEs with an index</h2>
|
||||||
|
<blockquote>
|
||||||
|
BEGIN;<br>
|
||||||
|
UPDATE t2 SET b=271822 WHERE a=1;<br>
|
||||||
|
UPDATE t2 SET b=28304 WHERE a=2;<br>
|
||||||
|
<i>... 24996 lines omitted</i><br>
|
||||||
|
UPDATE t2 SET b=442549 WHERE a=24999;<br>
|
||||||
|
UPDATE t2 SET b=423958 WHERE a=25000;<br>
|
||||||
|
COMMIT;<br>
|
||||||
|
|
||||||
<blockquote><pre>
|
</blockquote><table border=0 cellpadding=0 cellspacing=0>
|
||||||
UPDATE t1 SET f2=f3, f3=f2
|
<tr><td>PostgreSQL:</td><td align="right"> 28.021</td></tr>
|
||||||
WHERE f1 BETWEEN 15000 AND 20000;
|
<tr><td>MySQL:</td><td align="right"> 8.565</td></tr>
|
||||||
|
<tr><td>SQLite 2.4:</td><td align="right"> 10.939</td></tr>
|
||||||
PostgreSQL: real 6.56
|
<tr><td>SQLite 2.4 (nosync):</td><td align="right"> 11.199</td></tr>
|
||||||
SQLite 1.0: real 3.54 user 0.74 sys 1.16
|
</table>
|
||||||
SQLite 2.0: real 2.70 user 0.70 sys 1.25
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
We have no explanation for why PostgreSQL does poorly here.
|
In this case MySQL is slightly faster than SQLite, though not by much.
|
||||||
|
The difference is believed to have to do with the fact SQLite
|
||||||
|
handles the integers as strings instead of binary numbers.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Test 7: INSERT from a SELECT</h2>
|
<h2>Test 9: 25000 text UPDATEs with an index</h2>
|
||||||
|
<blockquote>
|
||||||
|
BEGIN;<br>
|
||||||
|
UPDATE t2 SET c='four hundred sixty eight thousand twenty six' WHERE a=1;<br>
|
||||||
|
UPDATE t2 SET c='one hundred twenty one thousand nine hundred twenty eight' WHERE a=2;<br>
|
||||||
|
<i>... 24996 lines omitted</i><br>
|
||||||
|
UPDATE t2 SET c='thirty five thousand sixty five' WHERE a=24999;<br>
|
||||||
|
UPDATE t2 SET c='three hundred forty seven thousand three hundred ninety three' WHERE a=25000;<br>
|
||||||
|
COMMIT;<br>
|
||||||
|
|
||||||
<blockquote><pre>
|
</blockquote><table border=0 cellpadding=0 cellspacing=0>
|
||||||
CREATE TABLE t2(f1 int, f2 int);
|
<tr><td>PostgreSQL:</td><td align="right"> 48.739</td></tr>
|
||||||
INSERT INTO t2 SELECT f1, f2 FROM t1 WHERE f3<10000;
|
<tr><td>MySQL:</td><td align="right"> 7.059</td></tr>
|
||||||
|
<tr><td>SQLite 2.4:</td><td align="right"> 7.868</td></tr>
|
||||||
PostgreSQL: real 2.05
|
<tr><td>SQLite 2.4 (nosync):</td><td align="right"> 6.720</td></tr>
|
||||||
SQLite 1.0: real 1.80 user 0.81 sys 0.73
|
</table>
|
||||||
SQLite 2.0: real 0.69 user 0.58 sys 0.07
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
|
|
||||||
<h2>Test 8: Many small INSERTs</h2>
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
CREATE TABLE t3(f1 int, f2 int, f3 int);
|
|
||||||
INSERT INTO t3 VALUES(1,1641,1019);
|
|
||||||
INSERT INTO t3 VALUES(2,984,477);
|
|
||||||
...
|
|
||||||
INSERT INTO t3 VALUES(998,1411,1392);
|
|
||||||
INSERT INTO t3 VALUES(999,1715,526);
|
|
||||||
INSERT INTO t3 VALUES(1000,1906,1037);
|
|
||||||
|
|
||||||
PostgreSQL: real 5.28
|
|
||||||
SQLite 1.0: real 2.20 user 0.21 sys 0.67
|
|
||||||
SQLite 2.0: real 10.99 user 0.21 sys 7.02
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
This test involves 1000 separate INSERT statements, only 5 of which
|
When updating a text field instead of an integer field,
|
||||||
are shown above. SQLite 2.0 does poorly because of its atomic commit
|
SQLite is slightly faster than MySQL.
|
||||||
logic. A minimum of two calls to <b>fsync()</b> are required for each
|
|
||||||
INSERT statement, and that really slows things down. On the other hand,
|
|
||||||
PostgreSQL also has to support atomic commits and it seems to do so
|
|
||||||
efficiently.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Test 9: Many small INSERTs within a TRANSACTION</h2>
|
<h2>Test 10: INSERTs from a SELECT</h2>
|
||||||
|
<blockquote>
|
||||||
<blockquote><pre>
|
BEGIN;<br>INSERT INTO t1 SELECT * FROM t2;<br>INSERT INTO t2 SELECT * FROM t1;<br>COMMIT;
|
||||||
CREATE TABLE t4(f1 int, f2 int, f3 int);
|
</blockquote><table border=0 cellpadding=0 cellspacing=0>
|
||||||
BEGIN TRANSACTION;
|
<tr><td>PostgreSQL:</td><td align="right"> 54.822</td></tr>
|
||||||
INSERT INTO t4 VALUES(1,440,1084);
|
<tr><td>MySQL:</td><td align="right"> 1.512</td></tr>
|
||||||
...
|
<tr><td>SQLite 2.4:</td><td align="right"> 4.423</td></tr>
|
||||||
INSERT INTO t4 VALUES(999,1527,423);
|
<tr><td>SQLite 2.4 (nosync):</td><td align="right"> 2.386</td></tr>
|
||||||
INSERT INTO t4 VALUES(1000,74,1865);
|
</table>
|
||||||
COMMIT;
|
|
||||||
|
|
||||||
PostgreSQL: real 0.68
|
|
||||||
SQLite 1.0: real 1.72 user 0.09 sys 0.55
|
|
||||||
SQLite 2.0: real 0.10 user 0.08 sys 0.02
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
By putting all the inserts inside a single transaction, there
|
The poor performance of PostgreSQL in this case appears to be due to its
|
||||||
only needs to be a single atomic commit at the very end. This
|
synchronous behavior. The CPU was mostly idle during the 55 second run.
|
||||||
allows SQLite 2.0 to go (literally) 100 times faster! PostgreSQL
|
|
||||||
only gets a eight-fold speedup. Perhaps PostgreSQL is limited here by
|
|
||||||
the IPC overhead.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Test 10: DELETE</h2>
|
<h2>Test 11: DELETE without an index</h2>
|
||||||
|
<blockquote>
|
||||||
|
DELETE FROM t2 WHERE c LIKE '%fifty%';
|
||||||
|
</blockquote><table border=0 cellpadding=0 cellspacing=0>
|
||||||
|
<tr><td>PostgreSQL:</td><td align="right"> 0.734</td></tr>
|
||||||
|
<tr><td>MySQL:</td><td align="right"> 0.888</td></tr>
|
||||||
|
<tr><td>SQLite 2.4:</td><td align="right"> 5.405</td></tr>
|
||||||
|
<tr><td>SQLite 2.4 (nosync):</td><td align="right"> 0.731</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
DELETE FROM t1 WHERE f2 NOT BETWEEN 10000 AND 20000;
|
|
||||||
|
|
||||||
PostgreSQL: real 7.25
|
<h2>Test 12: DELETE with an index</h2>
|
||||||
SQLite 1.0: real 6.98 user 1.66 sys 4.11
|
<blockquote>
|
||||||
SQLite 2.0: real 5.89 user 1.35 sys 3.11
|
DELETE FROM t2 WHERE a>10 AND a<20000;
|
||||||
</pre></blockquote>
|
</blockquote><table border=0 cellpadding=0 cellspacing=0>
|
||||||
|
<tr><td>PostgreSQL:</td><td align="right"> 2.318</td></tr>
|
||||||
|
<tr><td>MySQL:</td><td align="right"> 2.600</td></tr>
|
||||||
|
<tr><td>SQLite 2.4:</td><td align="right"> 1.436</td></tr>
|
||||||
|
<tr><td>SQLite 2.4 (nosync):</td><td align="right"> 0.775</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
<h2>Test 13: A big INSERT after a big DELETE</h2>
|
||||||
|
<blockquote>
|
||||||
|
INSERT INTO t2 SELECT * FROM t1;
|
||||||
|
</blockquote><table border=0 cellpadding=0 cellspacing=0>
|
||||||
|
<tr><td>PostgreSQL:</td><td align="right"> 63.867</td></tr>
|
||||||
|
<tr><td>MySQL:</td><td align="right"> 1.839</td></tr>
|
||||||
|
<tr><td>SQLite 2.4:</td><td align="right"> 3.971</td></tr>
|
||||||
|
<tr><td>SQLite 2.4 (nosync):</td><td align="right"> 1.993</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
All three database run at about the same speed here.
|
Earlier versions of SQLite would show decreasing performance after a
|
||||||
|
sequence DELETEs followed by new INSERTs. As this test shows, the
|
||||||
|
problem has now been resolved.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Test 11: DROP TABLE</h2>
|
<h2>Test 14: A big DELETE followed by many small INSERTs</h2>
|
||||||
|
<blockquote>
|
||||||
|
BEGIN;<br>
|
||||||
|
DELETE FROM t1;<br>
|
||||||
|
INSERT INTO t1 VALUES(1,29676,'twenty nine thousand six hundred seventy six');<br>
|
||||||
|
<i>... 2997 lines omitted</i><br>
|
||||||
|
INSERT INTO t1 VALUES(2999,37835,'thirty seven thousand eight hundred thirty five');<br>
|
||||||
|
INSERT INTO t1 VALUES(3000,97817,'ninety seven thousand eight hundred seventeen');<br>
|
||||||
|
COMMIT;<br>
|
||||||
|
|
||||||
<blockquote><pre>
|
</blockquote><table border=0 cellpadding=0 cellspacing=0>
|
||||||
BEGIN TRANSACTION;
|
<tr><td>PostgreSQL:</td><td align="right"> 1.209</td></tr>
|
||||||
DROP TABLE t1; DROP TABLE t2;
|
<tr><td>MySQL:</td><td align="right"> 1.031</td></tr>
|
||||||
DROP TABLE t3; DROP TABLE t4;
|
<tr><td>SQLite 2.4:</td><td align="right"> 0.298</td></tr>
|
||||||
COMMIT;
|
<tr><td>SQLite 2.4 (nosync):</td><td align="right"> 0.282</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
PostgreSQL: real 0.06
|
<h2>Test 15: DROP TABLE</h2>
|
||||||
SQLite 1.0: real 0.03 user 0.00 sys 0.02
|
<blockquote>
|
||||||
SQLite 2.0: real 3.12 user 0.02 sys 0.31
|
DROP TABLE t1;<br>DROP TABLE t2;
|
||||||
</pre></blockquote>
|
</blockquote><table border=0 cellpadding=0 cellspacing=0>
|
||||||
|
<tr><td>PostgreSQL:</td><td align="right"> 0.105</td></tr>
|
||||||
|
<tr><td>MySQL:</td><td align="right"> 0.015</td></tr>
|
||||||
|
<tr><td>SQLite 2.4:</td><td align="right"> 0.472</td></tr>
|
||||||
|
<tr><td>SQLite 2.4 (nosync):</td><td align="right"> 0.232</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
SQLite 2.0 is much slower at dropping tables. This may be because
|
SQLite is slower than the other databases when it comes to dropping tables.
|
||||||
both SQLite 1.0 and PostgreSQL can drop a table simply by unlinking
|
This is not seen as a big problem, however, since DROP TABLE is seldom
|
||||||
or renaming a file, since both store database tables in separate files.
|
used in speed-critical situations.
|
||||||
SQLite 2.0, on the other hand, uses a single file for the entire
|
|
||||||
database, so dropping a table involves moving lots of page of that
|
|
||||||
file to the free-list, which takes time.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user