Speed Comparison: SQLite, MySQL, PostgreSQL

This series of tests compares SQLcrypt™ with stock SQLite running on the same platform. The purpose is to measure the overhead introduced by SQLcrypt™'s storage-level cryptographic operations. The test script is speedtest-sqlcrypt.tcl and is adapted from SQLite's tools/speedtest.tcl.

The test script also tests MySQL and PostgreSQL. The intention is to get their numbers alongside SQLcrypt's and SQLite's, to provide a feel of how these database engines compare on the same platform, for these benchmarks. I shall discuss MySQL and PostgreSQL data encryption in a separate web page.

The version of MySQL used is the MySQL 4.1.7 Essential Windows installer. MySQL is configured for a developer workstation setup, using "multi-function storage", which means it uses both the original, fast ISAM storage and the newer, transaction-safe InnoBase storage. I do not know how MySQL decides which storage to use while running these tests. The MySQL installation is otherwise untuned.

The version of PostgreSQL used is 8.0.0 beta 4. Since this is a beta release, I have not included its numbers. I will do so when PostgreSQL version 8 is actually released.

Test Environment

The platform used for these tests is a Pentium III 833Mhz with 256MB RAM and an IDE 5400RPM disk. The operating system is Windows 98 SE2.

The first test creates an empty database, hence, for SQLcrypt™, it invokes the shell command ".encrypt" with the passphrase "passphrase". Subsequent tests invoke the shell command ".decrypt" because they are operating on an existing, encrypted database.

For each test, after SQLcrypt™ is done and before the other database engines are tested, the test input is modified to remove the commands ".encrypt" and ".decrypt" since these commands are specific to SQLcrypt™.

The times reported on all tests are wall-clock time in seconds. Both SQLite and SQLcrypt™ are tested with full disk synchronisation.

Test 1: 1000 INSERTs

.encrypt passphrase
CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100));
INSERT INTO t1 VALUES(1,13153,'thirteen thousand one hundred fifty three');
... 996 lines omitted
INSERT INTO t1 VALUES(998,66289,'sixty six thousand two hundred eighty nine');
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');
SQLcrypt 3.0.7:   8.049
SQLite 3.0.7:   3.741
MySQL 4.1.7:   1.400

Test 2: 25000 INSERTs in a transaction

.decrypt passphrase
BEGIN;
CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100));
... 24998 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');
COMMIT;
SQLcrypt 3.0.7:   8.672
SQLite 3.0.7:   2.734
MySQL 4.1.7:   17.099

Test 3: 100 SELECTs without an index

.decrypt passphrase
SELECT count(*), avg(b) FROM t2 WHERE b>=0 AND b<1000;
SELECT count(*), avg(b) FROM t2 WHERE b>=100 AND b<1100;
... 95 lines omitted
SELECT count(*), avg(b) FROM t2 WHERE b>=9700 AND b<10700;
SELECT count(*), avg(b) FROM t2 WHERE b>=9800 AND b<10800;
SELECT count(*), avg(b) FROM t2 WHERE b>=9900 AND b<10900;
SQLcrypt 3.0.7:   70.546
SQLite 3.0.7:   9.100
MySQL 4.1.7:   6.174

Test 4: 100 SELECTs on a string comparison

.decrypt passphrase
SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%one%';
SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%two%';
... 95 lines omitted
SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%ninety eight%';
SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%ninety nine%';
SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%one hundred%';
SQLcrypt 3.0.7:   88.458
SQLite 3.0.7:   13.416
MySQL 4.1.7:   8.644

Test 5: Creating an index

.decrypt passphrase
CREATE INDEX i2a ON t2(a);
CREATE INDEX i2b ON t2(b);
SQLcrypt 3.0.7:   7.203
SQLite 3.0.7:   1.427
MySQL 4.1.7:   3.838

Test 6: 5000 SELECTs with an index

.decrypt passphrase
SELECT count(*), avg(b) FROM t2 WHERE b>=0 AND b<100;
SELECT count(*), avg(b) FROM t2 WHERE b>=100 AND b<200;
... 4995 lines omitted
SELECT count(*), avg(b) FROM t2 WHERE b>=499700 AND b<499800;
SELECT count(*), avg(b) FROM t2 WHERE b>=499800 AND b<499900;
SELECT count(*), avg(b) FROM t2 WHERE b>=499900 AND b<500000;
SQLcrypt 3.0.7:   29.101
SQLite 3.0.7:   3.628
MySQL 4.1.7:   6.154

Test 7: 1000 UPDATEs without an index

.decrypt passphrase
BEGIN;
UPDATE t1 SET b=b*2 WHERE a>=0 AND a<10;
... 997 lines omitted
UPDATE t1 SET b=b*2 WHERE a>=9980 AND a<9990;
UPDATE t1 SET b=b*2 WHERE a>=9990 AND a<10000;
COMMIT;
SQLcrypt 3.0.7:   5.823
SQLite 3.0.7:   1.266
MySQL 4.1.7:   4.410

Test 8: 25000 UPDATEs with an index

.decrypt passphrase
BEGIN;
UPDATE t2 SET b=271822 WHERE a=1;
... 24997 lines omitted
UPDATE t2 SET b=442549 WHERE a=24999;
UPDATE t2 SET b=423958 WHERE a=25000;
COMMIT;
SQLcrypt 3.0.7:   61.533
SQLite 3.0.7:   6.954
MySQL 4.1.7:   24.721

Test 9: 25000 text UPDATEs with an index

.decrypt passphrase
BEGIN;
UPDATE t2 SET c='four hundred sixty eight thousand twenty six' WHERE a=1;
... 24997 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;
COMMIT;
SQLcrypt 3.0.7:   32.659
SQLite 3.0.7:   5.047
MySQL 4.1.7:   25.484

Test 10: INSERTs from a SELECT

.decrypt passphrase
BEGIN;
INSERT INTO t1 SELECT * FROM t2;
INSERT INTO t2 SELECT * FROM t1;
COMMIT;
SQLcrypt 3.0.7:   18.939
SQLite 3.0.7:   4.470
MySQL 4.1.7:   8.060

Test 11: DELETE without an index

.decrypt passphrase
DELETE FROM t2 WHERE c LIKE '%fifty%';
SQLcrypt 3.0.7:   15.323
SQLite 3.0.7:   2.921
MySQL 4.1.7:   4.066

Test 12: DELETE with an index

.decrypt passphrase
DELETE FROM t2 WHERE a>10 AND a<20000;
SQLcrypt 3.0.7:   16.232
SQLite 3.0.7:   1.989
MySQL 4.1.7:   4.758

Test 13: A big INSERT after a big DELETE

.decrypt passphrase
INSERT INTO t2 SELECT * FROM t1;
SQLcrypt 3.0.7:   23.579
SQLite 3.0.7:   3.530
MySQL 4.1.7:   3.330

Test 14: A big DELETE followed by many small INSERTs

.decrypt passphrase
BEGIN;
DELETE FROM t1;
... 2998 lines omitted
INSERT INTO t1 VALUES(2999,37835,'thirty seven thousand eight hundred thirty five');
INSERT INTO t1 VALUES(3000,97817,'ninety seven thousand eight hundred seventeen');
COMMIT;
SQLcrypt 3.0.7:   2.818
SQLite 3.0.7:   0.785
MySQL 4.1.7:   3.695

Test 15: DROP TABLE

.decrypt passphrase
DROP TABLE t1;
DROP TABLE t2;
SQLcrypt 3.0.7:   3.811
SQLite 3.0.7:   2.155
MySQL 4.1.7:   0.415