diff --git a/manifest b/manifest index 6e7c3aa864..3a6a1a7c83 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sasserts\sto\sbtree.c\sthat\scheck\sfor\sthe\scorrect\ssize\sof\svarious\stypedefs\nand\sstructures.\s\sTicket\s#233.\s(CVS\s845) -D 2003-01-24T12:14:20 +C Update\sthe\sspeed.html\sdocumentation.\s\sRecent\soptimizations\shave\smade\sthe\nlibrary\smuch\sfaster.\s(CVS\s846) +D 2003-01-25T14:25:42 F Makefile.in 6606854b1512f185b8e8c779b8d7fc2750463d64 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -150,11 +150,11 @@ F www/nulls.tcl 29497dac2bc5b437aa7e2e94577dad4d8933ed26 F www/omitted.tcl 118062f40a203fcb88b8d68ef1d7c0073ac191ec F www/opcode.tcl 33c5f2061a05c5d227c72b84c080b3bf74c74f8b F www/quickstart.tcl 368d7ef130274307accceb2e21c9fc70bbb0ba65 -F www/speed.tcl 52759968401d81760fc01f9d3ab6242f6d2a7066 +F www/speed.tcl 4d463e2aea41f688ed320a937f93ff885be918c3 F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 -P 19221dee5fee4c8800cbae309f009964c8d646a2 -R 5f54a128edf3ccd559b45b128151fef3 +P c7e647d011b086a6e57420850f6bc4f28fcb23ee +R fb265d63c9802489e93e63983e966b97 U drh -Z a3694ca5aa529fbe36a1167d1cb0514e +Z 9cebef5aee83f0a69d880740ef12b3fa diff --git a/manifest.uuid b/manifest.uuid index c51d816a09..b3a89d579e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c7e647d011b086a6e57420850f6bc4f28fcb23ee \ No newline at end of file +ed47d162a072a2f98b633cc14f2be1474288d90b \ No newline at end of file diff --git a/www/speed.tcl b/www/speed.tcl index e71c8dd84f..3ca6dfccb0 100644 --- a/www/speed.tcl +++ b/www/speed.tcl @@ -1,7 +1,7 @@ # # Run this Tcl script to generate the speed.html file. # -set rcsid {$Id: speed.tcl,v 1.9 2003/01/18 22:01:07 drh Exp $ } +set rcsid {$Id: speed.tcl,v 1.10 2003/01/25 14:25:42 drh Exp $ } puts { @@ -31,15 +31,19 @@ conclusions drawn from these experiments: for most common operations.

  • - SQLite 2.7.6 is usually faster than MySQL 3.23.41 (sometimes - more than twice as fast) though for some operations such as - full table scans, it can be as much as 30% slower. + SQLite 2.7.6 is often faster (sometimes + more than twice as fast) than MySQL 3.23.41 + for most common operations.

  • SQLite does not execute CREATE INDEX or DROP TABLE as fast as the other databases. But this as not seen is a problem because those are infrequent operations.

  • +
  • + SQLite works best if you group multiple operations together into + a single transaction. +

  • @@ -52,7 +56,7 @@ The results presented here come with the following caveats: optimization of complex queries involving multiple joins and subqueries.

  • - These tests are on a relatively small (approximately 10 megabyte) database. + These tests are on a relatively small (approximately 14 megabyte) database. They do not measure how well the database engines scale to larger problems.

  • @@ -127,44 +131,75 @@ INSERT INTO t1 VALUES(999,24322,'twenty four thousand three hundred twenty two') INSERT INTO t1 VALUES(1000,94142,'ninety four thousand one hundred forty two');
    - - - - + + + +
    PostgreSQL:   3.658
    MySQL:   0.109
    SQLite 2.7.6:   7.177
    SQLite 2.7.6 (nosync):   0.266
    PostgreSQL:   4.373
    MySQL:   0.114
    SQLite 2.7.6:   13.061
    SQLite 2.7.6 (nosync):   0.223
    -

    SQLite must close and reopen the database file, and thus invalidate -its cache, for each SQL statement. In spite of this, the asynchronous +

    +Because it does not have a central server to coordinate access, +SQLite must close and reopen the database file, and thus invalidate +its cache, for each transaction. In this test, each SQL statement +is a separate transaction so the database file must be opened and closed +and the cache must be flushed 1000 times. 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 fsync() after each SQL statement.

    +the synchronous version is, however. SQLite calls fsync() after +each synchronous transaction to make sure that all data is safely on +the disk surface before continuing. For most of the 13 seconds in the +synchronous test, SQLite was sitting idle waiting on disk I/O to complete.

    Test 2: 25000 INSERTs in a transaction

    BEGIN;
    CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100));
    -INSERT INTO t2 VALUES(1,298361,'two hundred ninety eight thousand three hundred sixty one');
    +INSERT INTO t2 VALUES(1,59672,'fifty nine thousand six hundred seventy two');
    ... 24997 lines omitted
    -INSERT INTO t2 VALUES(24999,447847,'four hundred forty seven thousand eight hundred forty seven');
    -INSERT INTO t2 VALUES(25000,473330,'four hundred seventy three thousand three hundred thirty');
    +INSERT INTO t2 VALUES(24999,89569,'eighty nine thousand five hundred sixty nine');
    +INSERT INTO t2 VALUES(25000,94666,'ninety four thousand six hundred sixty six');
    COMMIT;
    - - - - + + + +
    PostgreSQL:   5.058
    MySQL:   2.271
    SQLite 2.7.6:   0.912
    SQLite 2.7.6 (nosync):   0.798
    PostgreSQL:   4.900
    MySQL:   2.184
    SQLite 2.7.6:   0.914
    SQLite 2.7.6 (nosync):   0.757

    When all the INSERTs are put in a transaction, SQLite no longer has to -close and reopen the database between each statement. It also does not +close and reopen the database or invalidate its cache between each statement. +It also does not have to do any fsync()s until the very end. When unshackled in this way, SQLite is much faster than either PostgreSQL and MySQL.

    -

    Test 3: 100 SELECTs without an index

    +

    Test 3: 25000 INSERTs into an indexed tablel

    +
    +BEGIN;
    +CREATE TABLE t3(a INTEGER, b INTEGER, c VARCHAR(100));
    +CREATE INDEX i3 ON t3(c);
    +... 24998 lines omitted
    +INSERT INTO t3 VALUES(24999,88509,'eighty eight thousand five hundred nine');
    +INSERT INTO t3 VALUES(25000,84791,'eighty four thousand seven hundred ninety one');
    +COMMIT;
    + +
    + + + + +
    PostgreSQL:   8.175
    MySQL:   3.197
    SQLite 2.7.6:   1.555
    SQLite 2.7.6 (nosync):   1.402
    + +

    +There were reports that SQLite did not perform as well on an indexed table. +This test was recently added to disprove those rumors. It is true that +SQLite is not as fast at creating new index entries as the other engines +(see Test 6 below) but its overall speed is still better. +

    + +

    Test 4: 100 SELECTs without an index

    BEGIN;
    SELECT count(*), avg(b) FROM t2 WHERE b>=0 AND b<1000;
    @@ -175,25 +210,22 @@ SELECT count(*), avg(b) FROM t2 WHERE b>=9900 AND b<10900;
    COMMIT;
    - - - - + + + +
    PostgreSQL:   3.657
    MySQL:   3.368
    SQLite 2.7.6:   4.386
    SQLite 2.7.6 (nosync):   4.314
    PostgreSQL:   3.629
    MySQL:   2.760
    SQLite 2.7.6:   2.494
    SQLite 2.7.6 (nosync):   2.526
    +

    This test does 100 queries on a 25000 entry table without an index, -thus requiring a full table scan. SQLite is about 20% or 30% slower -than PostgreSQL and MySQL. The reason for this is believed to be -because SQLite stores all data as strings -and must therefore do 5 million string-to-number conversions 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. +thus requiring a full table scan. Prior versions of SQLite used to +be slower than PostgreSQL and MySQL on this test, but recent performance +enhancements have increased its speed so that it is now the fastest +of the group.

    - -

    Test 4: 100 SELECTs on a string comparison

    +

    Test 5: 100 SELECTs on a string comparison

    BEGIN;
    SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%one%';
    @@ -204,37 +236,37 @@ SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%one hundred%';
    COMMIT;
    - - - - + + + +
    PostgreSQL:   15.967
    MySQL:   5.088
    SQLite 2.7.6:   5.419
    SQLite 2.7.6 (nosync):   5.367
    PostgreSQL:   13.409
    MySQL:   4.640
    SQLite 2.7.6:   3.362
    SQLite 2.7.6 (nosync):   3.372

    This test still does 100 full table scans but it uses uses string comparisons instead of numerical comparisions. -SQLite is almost three times faster than PostgreSQL here. But it is -still 15% slower than MySQL. MySQL appears to be very good -at doing full table scans. +SQLite is over three times faster than PostgreSQL here and about 30% +faster than MySQL.

    -

    Test 5: Creating an index

    +

    Test 6: Creating an index

    CREATE INDEX i2a ON t2(a);
    CREATE INDEX i2b ON t2(b);
    - - - - + + + +
    PostgreSQL:   0.431
    MySQL:   0.340
    SQLite 2.7.6:   0.814
    SQLite 2.7.6 (nosync):   0.675
    PostgreSQL:   0.381
    MySQL:   0.318
    SQLite 2.7.6:   0.777
    SQLite 2.7.6 (nosync):   0.659

    -SQLite is slower at creating new indices. But since creating -new indices is an uncommon operation, this is not seen as a -problem. +SQLite is slower at creating new indices. This is not a huge problem +(since new indices are not created very often) but it is something that +is being worked on. Hopefully, future versions of SQLite will do better +here.

    -

    Test 6: 5000 SELECTs with an index

    +

    Test 7: 5000 SELECTs with an index

    SELECT count(*), avg(b) FROM t2 WHERE b>=0 AND b<100;
    SELECT count(*), avg(b) FROM t2 WHERE b>=100 AND b<200;
    @@ -245,19 +277,18 @@ SELECT count(*), avg(b) FROM t2 WHERE b>=499800 AND b<499900;
    SELECT count(*), avg(b) FROM t2 WHERE b>=499900 AND b<500000;
    - - - - + + + +
    PostgreSQL:   5.369
    MySQL:   1.489
    SQLite 2.7.6:   1.423
    SQLite 2.7.6 (nosync):   1.358
    PostgreSQL:   4.614
    MySQL:   1.270
    SQLite 2.7.6:   1.121
    SQLite 2.7.6 (nosync):   1.162

    -This test runs a set of 5000 queries that are similar in form to -those in test 3. But now instead of being slower, SQLite -is faster than both PostgreSQL and MySQL. +All three database engines run faster when they have indices to work with. +But SQLite is still the fastest.

    -

    Test 7: 1000 UPDATEs without an index

    +

    Test 8: 1000 UPDATEs without an index

    BEGIN;
    UPDATE t1 SET b=b*2 WHERE a>=0 AND a<10;
    @@ -268,10 +299,10 @@ UPDATE t1 SET b=b*2 WHERE a>=9990 AND a<10000;
    COMMIT;
    - - - - + + + +
    PostgreSQL:   1.740
    MySQL:   8.162
    SQLite 2.7.6:   0.635
    SQLite 2.7.6 (nosync):   0.608
    PostgreSQL:   1.739
    MySQL:   8.410
    SQLite 2.7.6:   0.637
    SQLite 2.7.6 (nosync):   0.638

    @@ -282,44 +313,44 @@ normally a very fast engine. Perhaps this problem has been addressed in later versions of MySQL.

    -

    Test 8: 25000 UPDATEs with an index

    +

    Test 9: 25000 UPDATEs with an index

    BEGIN;
    -UPDATE t2 SET b=271822 WHERE a=1;
    -UPDATE t2 SET b=28304 WHERE a=2;
    +UPDATE t2 SET b=468026 WHERE a=1;
    +UPDATE t2 SET b=121928 WHERE a=2;
    ... 24996 lines omitted
    -UPDATE t2 SET b=442549 WHERE a=24999;
    -UPDATE t2 SET b=423958 WHERE a=25000;
    +UPDATE t2 SET b=35065 WHERE a=24999;
    +UPDATE t2 SET b=347393 WHERE a=25000;
    COMMIT;
    - - - - + + + +
    PostgreSQL:   32.118
    MySQL:   8.132
    SQLite 2.7.6:   4.109
    SQLite 2.7.6 (nosync):   3.712
    PostgreSQL:   18.797
    MySQL:   8.134
    SQLite 2.7.6:   3.520
    SQLite 2.7.6 (nosync):   3.104

    As recently as version 2.7.0, SQLite ran at about the same speed as -MySQL on this test. But recent optimizations to SQLite have doubled -speed of UPDATEs. +MySQL on this test. But recent optimizations to SQLite have more +than doubled speed of UPDATEs.

    -

    Test 9: 25000 text UPDATEs with an index

    +

    Test 10: 25000 text UPDATEs with an index

    BEGIN;
    -UPDATE t2 SET c='four hundred sixty eight thousand twenty six' WHERE a=1;
    -UPDATE t2 SET c='one hundred twenty one thousand nine hundred twenty eight' WHERE a=2;
    +UPDATE t2 SET c='one hundred forty eight thousand three hundred eighty two' WHERE a=1;
    +UPDATE t2 SET c='three hundred sixty six thousand five hundred two' WHERE a=2;
    ... 24996 lines omitted
    -UPDATE t2 SET c='thirty five thousand sixty five' WHERE a=24999;
    -UPDATE t2 SET c='three hundred forty seven thousand three hundred ninety three' WHERE a=25000;
    +UPDATE t2 SET c='three hundred eighty three thousand ninety nine' WHERE a=24999;
    +UPDATE t2 SET c='two hundred fifty six thousand eight hundred thirty' WHERE a=25000;
    COMMIT;
    - - - - + + + +
    PostgreSQL:   55.309
    MySQL:   6.585
    SQLite 2.7.6:   2.474
    SQLite 2.7.6 (nosync):   1.800
    PostgreSQL:   48.133
    MySQL:   6.982
    SQLite 2.7.6:   2.408
    SQLite 2.7.6 (nosync):   1.725

    @@ -328,50 +359,53 @@ as MySQL. But now version 2.7.6 is over two times faster than MySQL and over twenty times faster than PostgreSQL.

    -

    Test 10: INSERTs from a SELECT

    +

    +In fairness to PostgreSQL, it started thrashing on this test. A +knowledgeable administrator might be able to get PostgreSQL to run a lot +faster here by tweaking and tuning the server a little. +

    + +

    Test 11: INSERTs from a SELECT

    BEGIN;
    INSERT INTO t1 SELECT b,a,c FROM t2;
    INSERT INTO t2 SELECT b,a,c FROM t1;
    COMMIT;
    - - - - + + + +
    PostgreSQL:   58.956
    MySQL:   1.465
    SQLite 2.7.6:   2.926
    SQLite 2.7.6 (nosync):   1.664
    PostgreSQL:   61.364
    MySQL:   1.537
    SQLite 2.7.6:   2.787
    SQLite 2.7.6 (nosync):   1.599

    -The poor performance of PostgreSQL in this case appears to be due to its -synchronous behavior. The CPU was mostly idle the test run. Presumably, -PostgreSQL was spending most of its time waiting on disk I/O to complete. -I'm not sure why SQLite performs poorly here. It use to be quicker at this -test, but the same enhancements that sped up the UPDATE logic seem to have -slowed down this test. +The asynchronous SQLite is just a shade slower than MySQL on this test. +(MySQL seems to be especially adept at INSERT...SELECT statements.) +The PostgreSQL engine is still thrashing - most of the 61 seconds it used +were spent waiting on disk I/O.

    -

    Test 11: DELETE without an index

    +

    Test 12: DELETE without an index

    DELETE FROM t2 WHERE c LIKE '%fifty%';
    - - - - + + + +
    PostgreSQL:   1.365
    MySQL:   0.849
    SQLite 2.7.6:   4.005
    SQLite 2.7.6 (nosync):   0.631
    PostgreSQL:   1.509
    MySQL:   0.975
    SQLite 2.7.6:   4.004
    SQLite 2.7.6 (nosync):   0.560

    The synchronous version of SQLite is the slowest of the group in this test, -but the asynchronous version is the fastest. SQLite used about the same -amount of CPU time in both versions; the difference is the extra time needed -to write information to the disk surface. +but the asynchronous version is the fastest. +The difference is the extra time needed to execute fsync().

    -

    Test 12: DELETE with an index

    +

    Test 13: DELETE with an index

    DELETE FROM t2 WHERE a>10 AND a<20000;
    - - - - + + + +
    PostgreSQL:   1.340
    MySQL:   2.167
    SQLite 2.7.6:   2.344
    SQLite 2.7.6 (nosync):   0.858
    PostgreSQL:   1.316
    MySQL:   2.262
    SQLite 2.7.6:   2.068
    SQLite 2.7.6 (nosync):   0.752

    @@ -380,38 +414,38 @@ PostgreSQL is faster than MySQL. The asynchronous SQLite is, however, faster then both the other two.

    - -

    Test 13: A big INSERT after a big DELETE

    +

    Test 14: A big INSERT after a big DELETE

    INSERT INTO t2 SELECT * FROM t1;
    - - - - + + + +
    PostgreSQL:   12.672
    MySQL:   1.837
    SQLite 2.7.6:   3.076
    SQLite 2.7.6 (nosync):   1.570
    PostgreSQL:   13.168
    MySQL:   1.815
    SQLite 2.7.6:   3.210
    SQLite 2.7.6 (nosync):   1.485

    -Some older versions of SQLite would show decreasing performance after a -sequence DELETEs followed by new INSERTs. As this test shows, the +Some older versions of SQLite (prior to version 2.4.0) +would show decreasing performance after a +sequence of DELETEs followed by new INSERTs. As this test shows, the problem has now been resolved.

    -

    Test 14: A big DELETE followed by many small INSERTs

    +

    Test 15: A big DELETE followed by many small INSERTs

    BEGIN;
    DELETE FROM t1;
    -INSERT INTO t1 VALUES(1,29676,'twenty nine thousand six hundred seventy six');
    +INSERT INTO t1 VALUES(1,10719,'ten thousand seven hundred nineteen');
    ... 11997 lines omitted
    -INSERT INTO t1 VALUES(11999,71818,'seventy one thousand eight hundred eighteen');
    -INSERT INTO t1 VALUES(12000,58579,'fifty eight thousand five hundred seventy nine');
    +INSERT INTO t1 VALUES(11999,72836,'seventy two thousand eight hundred thirty six');
    +INSERT INTO t1 VALUES(12000,64231,'sixty four thousand two hundred thirty one');
    COMMIT;
    - - - - + + + +
    PostgreSQL:   4.165
    MySQL:   1.733
    SQLite 2.7.6:   0.652
    SQLite 2.7.6 (nosync):   0.465
    PostgreSQL:   4.556
    MySQL:   1.704
    SQLite 2.7.6:   0.618
    SQLite 2.7.6 (nosync):   0.406

    @@ -419,14 +453,14 @@ SQLite is very good at doing INSERTs within a transaction, which probably explains why it is so much faster than the other databases at this test.

    -

    Test 15: DROP TABLE

    +

    Test 16: DROP TABLE

    -DROP TABLE t1;
    DROP TABLE t2; +DROP TABLE t1;
    DROP TABLE t2;
    DROP TABLE t3;
    - - - - + + + +
    PostgreSQL:   0.133
    MySQL:   0.014
    SQLite 2.7.6:   0.873
    SQLite 2.7.6 (nosync):   0.224
    PostgreSQL:   0.135
    MySQL:   0.015
    SQLite 2.7.6:   0.939
    SQLite 2.7.6 (nosync):   0.254