小巧。快速。可靠。
三选二。

数据库速度比较

注意:本文档非常非常旧。它描述了 SQLite、MySQL 和 PostgreSQL 的早期版本的比较。

此处的数字已失去意义。此页面仅作为历史记录保留。

执行摘要

进行了一系列测试,以衡量 SQLite 2.7.6、PostgreSQL 7.1.3 和 MySQL 3.23.41 的相对性能。以下是从这些实验中得出的总体结论

此处提供的结果带有以下注意事项

测试环境

这些测试使用的平台是 1.6GHz Athlon,配备 1GB 内存和 IDE 磁盘驱动器。操作系统是 RedHat Linux 7.2,使用标准内核。

使用的 PostgreSQL 和 MySQL 服务器是 RedHat 7.2 上默认提供的。(PostgreSQL 版本 7.1.3 和 MySQL 版本 3.23.41。)没有进行任何尝试来调整这些引擎。特别要注意 RedHat 7.2 上的默认 MySQL 配置不支持事务。无需支持事务使 MySQL 具有很大的速度优势,但 SQLite 仍然能够在大多数测试中保持其自身的速度。

据我了解,RedHat 7.3 中的默认 PostgreSQL 配置过于保守(它旨在在一台拥有 8MB RAM 的机器上运行),并且可以通过一些专业的配置调整使 PostgreSQL 运行得更快。Matt Sergeant 报告说,他已经调整了他的 PostgreSQL 安装并重新运行了下面显示的测试。他的结果表明,PostgreSQL 和 MySQL 的运行速度大致相同。有关 Matt 的结果,请访问

已失效的 URL:http://www.sergeant.org/sqlite_vs_pgsync.html

SQLite 在与网站上显示的相同配置中进行了测试。它使用 -O6 优化和 -DNDEBUG=1 开关进行编译,该开关禁用 SQLite 代码中的许多“assert()”语句。-DNDEBUG=1 编译器选项使 SQLite 的速度大约提高了一倍。

所有测试都在其他方面处于静止状态的机器上进行。一个简单的 Tcl 脚本用于生成和运行所有测试。此 Tcl 脚本的副本可以在 SQLite 源代码树中的 tools/speedtest.tcl 文件中找到。

所有测试中报告的时间代表以秒为单位的挂钟时间。SQLite 报告了两个单独的时间值。第一个值是 SQLite 在其默认配置下启用完整磁盘同步时的值。启用同步后,SQLite 会在关键点执行 fsync() 系统调用(或等效调用),以确保关键数据已实际写入磁盘驱动器表面。如果操作系统崩溃或计算机在数据库更新过程中意外断电,则同步对于保证数据库的完整性是必要的。SQLite 报告的第二个时间是在禁用同步时。禁用同步后,SQLite 有时会快得多,但存在操作系统崩溃或意外断电可能损坏数据库的风险。一般来说,同步 SQLite 时间用于与 PostgreSQL(也同步)进行比较,异步 SQLite 时间用于与异步 MySQL 引擎进行比较。

测试 1:1000 个 INSERT

CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100));
INSERT INTO t1 VALUES(1,13153,'thirteen thousand one hundred fifty three');
INSERT INTO t1 VALUES(2,75560,'seventy five thousand five hundred sixty');
... 省略了 995 行
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');
PostgreSQL   4.373
MySQL   0.114
SQLite 2.7.6   13.061
SQLite 2.7.6 (nosync)   0.223

由于 SQLite 没有中央服务器来协调访问,因此它必须关闭并重新打开数据库文件,从而使缓存失效,以进行每个事务。在此测试中,每个 SQL 语句都是一个单独的事务,因此数据库文件必须打开和关闭,并且缓存必须刷新 1000 次。尽管如此,SQLite 的异步版本仍然几乎与 MySQL 一样快。但是,请注意同步版本的运行速度慢了多少。SQLite 在每个同步事务后都会调用 fsync(),以确保所有数据在继续之前都安全地位于磁盘表面。在同步测试中的 13 秒的大部分时间里,SQLite 处于空闲状态,等待磁盘 I/O 完成。

测试 2:在一个事务中进行 25000 个 INSERT

BEGIN;
CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100));
INSERT INTO t2 VALUES(1,59672,'fifty nine thousand six hundred seventy two');
... 省略了 24997 行
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   4.900
MySQL   2.184
SQLite 2.7.6   0.914
SQLite 2.7.6 (nosync)   0.757

当所有 INSERT 都放在一个事务中时,SQLite 不再需要在每个语句之间关闭和重新打开数据库或使缓存失效。它也不必在最后之前执行任何 fsync()。在这种情况下,SQLite 比 PostgreSQL 和 MySQL 都快得多。

测试 3:将 25000 个 INSERT 插入到索引表中

BEGIN;
CREATE TABLE t3(a INTEGER, b INTEGER, c VARCHAR(100));
CREATE INDEX i3 ON t3(c);
... 省略了 24998 行
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

有报告称 SQLite 在索引表上的性能不佳。最近添加了此测试以反驳这些谣言。确实,SQLite 创建新索引条目的速度不如其他引擎快(请参阅下面的测试 6),但其整体速度仍然更好。

测试 4:100 个没有索引的 SELECT

BEGIN;
SELECT count(*), avg(b) FROM t2 WHERE b>=0 AND b<1000;
SELECT count(*), avg(b) FROM t2 WHERE b>=100 AND b<1100;
... 省略了 96 行
SELECT count(*), avg(b) FROM t2 WHERE b>=9800 AND b<10800;
SELECT count(*), avg(b) FROM t2 WHERE b>=9900 AND b<10900;
COMMIT;
PostgreSQL   3.629
MySQL   2.760
SQLite 2.7.6   2.494
SQLite 2.7.6 (nosync)   2.526

此测试对一个没有索引的 25000 条记录的表执行 100 个查询,因此需要进行完全表扫描。早期版本的 SQLite 在此测试中曾经比 PostgreSQL 和 MySQL 慢,但最近的性能增强提高了它的速度,使其现在成为该组中最快的。

测试 5:100 个字符串比较的 SELECT

BEGIN;
SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%one%';
SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%two%';
... 省略了 96 行
SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%ninety nine%';
SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%one hundred%';
COMMIT;
PostgreSQL   13.409
MySQL   4.640
SQLite 2.7.6   3.362
SQLite 2.7.6 (nosync)   3.372

此测试仍然执行 100 个完全表扫描,但它使用字符串比较而不是数值比较。SQLite 在此处的速度是 PostgreSQL 的三倍以上,比 MySQL 快约 30%。

测试 6:创建索引

CREATE INDEX i2a ON t2(a);
CREATE INDEX i2b ON t2(b);
PostgreSQL   0.381
MySQL   0.318
SQLite 2.7.6   0.777
SQLite 2.7.6 (nosync)   0.659

SQLite 创建新索引的速度较慢。这不是一个大问题(因为不会经常创建新索引),但它是一个正在解决的问题。希望 SQLite 的未来版本在这里能做得更好。

测试 7:使用索引进行 5000 个 SELECT

SELECT count(*), avg(b) FROM t2 WHERE b>=0 AND b<100;
SELECT count(*), avg(b) FROM t2 WHERE b>=100 AND b<200;
SELECT count(*), avg(b) FROM t2 WHERE b>=200 AND b<300;
... 省略了 4994 行
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;
PostgreSQL   4.614
MySQL   1.270
SQLite 2.7.6   1.121
SQLite 2.7.6 (nosync)   1.162

当三个数据库引擎都使用索引时,它们的运行速度都会更快。但 SQLite 仍然最快。

测试 8:1000 个没有索引的 UPDATE

BEGIN;
UPDATE t1 SET b=b*2 WHERE a>=0 AND a<10;
UPDATE t1 SET b=b*2 WHERE a>=10 AND a<20;
... 省略了 996 行
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;
PostgreSQL   1.739
MySQL   8.410
SQLite 2.7.6   0.637
SQLite 2.7.6 (nosync)   0.638

对于此特定的 UPDATE 测试,MySQL 的速度始终比 PostgreSQL 和 SQLite 慢五到十倍。我不知道为什么。MySQL 通常是一个非常快的引擎。也许这个问题在 MySQL 的后续版本中已经得到了解决。

测试 9:使用索引进行 25000 个 UPDATE

BEGIN;
UPDATE t2 SET b=468026 WHERE a=1;
UPDATE t2 SET b=121928 WHERE a=2;
... 省略了 24996 行
UPDATE t2 SET b=35065 WHERE a=24999;
UPDATE t2 SET b=347393 WHERE a=25000;
COMMIT;
PostgreSQL   18.797
MySQL   8.134
SQLite 2.7.6   3.520
SQLite 2.7.6 (nosync)   3.104

直到 2.7.0 版本,SQLite 在此测试中的运行速度与 MySQL 相当。但是,SQLite 的最近优化使 UPDATE 的速度提高了一倍多。

测试 10:使用索引进行 25000 个文本 UPDATE

BEGIN;
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 行
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   48.133
MySQL   6.982
SQLite 2.7.6   2.408
SQLite 2.7.6 (nosync)   1.725

同样,SQLite 的 2.7.0 版本曾经与 MySQL 的运行速度相当。但现在 2.7.6 版本的速度是 MySQL 的两倍以上,是 PostgreSQL 的二十倍以上。

公平起见,PostgreSQL 在此测试中开始出现抖动。一位经验丰富的管理员可以通过稍微调整和优化服务器来大幅提升 PostgreSQL 的运行速度。

测试 11:从 SELECT 中插入数据

BEGIN;
INSERT INTO t1 SELECT b,a,c FROM t2;
INSERT INTO t2 SELECT b,a,c FROM t1;
COMMIT;
PostgreSQL   61.364
MySQL   1.537
SQLite 2.7.6   2.787
SQLite 2.7.6 (nosync)   1.599

异步 SQLite 在此测试中仅略微慢于 MySQL。(MySQL 似乎特别擅长 INSERT...SELECT 语句。)PostgreSQL 引擎仍在抖动 - 它使用的 61 秒中的大部分时间都花在了等待磁盘 I/O 上。

测试 12:无索引的 DELETE

DELETE FROM t2 WHERE c LIKE '%fifty%';
PostgreSQL   1.509
MySQL   0.975
SQLite 2.7.6   4.004
SQLite 2.7.6 (nosync)   0.560

在此测试中,SQLite 的同步版本是最慢的,但异步版本是最快的。区别在于执行 fsync() 所需的额外时间。

测试 13:有索引的 DELETE

DELETE FROM t2 WHERE a>10 AND a<20000;
PostgreSQL   1.316
MySQL   2.262
SQLite 2.7.6   2.068
SQLite 2.7.6 (nosync)   0.752

此测试意义重大,因为它是在少数 PostgreSQL 比 MySQL 更快的测试之一。但是,异步 SQLite 比这两个都要快。

测试 14:大型 DELETE 之后的大型 INSERT

INSERT INTO t2 SELECT * FROM t1;
PostgreSQL   13.168
MySQL   1.815
SQLite 2.7.6   3.210
SQLite 2.7.6 (nosync)   1.485

一些较旧版本的 SQLite(版本 2.4.0 之前)在执行一系列 DELETE 后再执行新的 INSERT 时,性能会下降。如本测试所示,此问题现已解决。

测试 15:大型 DELETE 后跟许多小型 INSERT

BEGIN;
DELETE FROM t1;
INSERT INTO t1 VALUES(1,10719,'ten thousand seven hundred nineteen');
... 省略了 11997 行
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.556
MySQL   1.704
SQLite 2.7.6   0.618
SQLite 2.7.6 (nosync)   0.406

SQLite 非常擅长在事务中执行 INSERT 操作,这可能是它在此测试中比其他数据库快得多的原因。

测试 16:DROP TABLE

DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t3;
PostgreSQL   0.135
MySQL   0.015
SQLite 2.7.6   0.939
SQLite 2.7.6 (nosync)   0.254

在删除表方面,SQLite 比其他数据库慢。这可能是因为当 SQLite 删除表时,它必须遍历并擦除数据库文件中处理该表的所有记录。另一方面,MySQL 和 PostgreSQL 使用单独的文件来表示每个表,因此它们可以通过简单地删除文件来删除表,这速度快得多。

另一方面,删除表并不是一项非常常见的操作,因此如果 SQLite 花费的时间稍长一些,这不会被视为一个大问题。

此页面上次修改于 2023-01-02 14:22:42 UTC