数据库速度比较
注意:这份文件非常非常旧。它描述了 SQLite、MySQL 和 PostgreSQL 的古老版本之间的速度比较。这里的数字已经变得毫无意义。此页面仅作为历史文物保留。
执行摘要
运行了一系列测试来衡量 SQLite 2.7.6、PostgreSQL 7.1.3 和 MySQL 3.23.41 的相对性能。以下是从这些实验得出的一般结论:
对于大多数常见操作,SQLite 2.7.6 比 RedHat 7.2 上默认的 PostgreSQL 7.1.3 安装快得多(有时快 10 或 20 倍)。
对于大多数常见操作,SQLite 2.7.6 通常比 MySQL 3.23.41 更快(有时快两倍以上)。
SQLite 执行 CREATE INDEX 或 DROP TABLE 的速度不如其他数据库。但这并不被视为问题,因为这些操作并不频繁。
如果将多个操作组合到一个事务中,SQLite 的效果最好。
此处显示的结果带有以下警告:
这些测试并未尝试测量多用户性能或涉及多个连接和子查询的复杂查询的优化。
这些测试是在一个相对较小(大约 14 兆字节)的数据库上进行的。它们不衡量数据库引擎扩展到更大问题的能力。
测试环境
用于这些测试的平台是一个 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 的结果,请访问
http://www.sergeant.org/sqlite_vs_pgsync.html
SQLite 在网站上显示的相同配置中进行了测试。它是使用 -O6 优化和 -DNDEBUG=1 开关编译的,该开关禁用了 SQLite 代码中的许多“assert()”语句。-DNDEBUG=1 编译器选项大致使 SQLite 的速度加倍。
所有测试都在一台静止的机器上进行。一个简单的 Tcl 脚本用于生成和运行所有测试。可以在文件tools/speedtest.tcl的 SQLite 源代码树中找到此 Tcl 脚本的副本。
所有测试报告的时间代表以秒为单位的挂钟时间。为 SQLite 报告了两个单独的时间值。第一个值是针对 SQLite 的默认配置,并启用了全磁盘同步。开启同步后,SQLite 执行一个fsync()在关键点进行系统调用(或等效),以确保关键数据已实际写入磁盘驱动器表面。如果操作系统崩溃或计算机在数据库更新过程中意外断电,则必须进行同步以保证数据库的完整性。第二次报告 SQLite 是在同步关闭时。关闭同步后,SQLite 有时会快得多,但存在操作系统崩溃或意外电源故障可能损坏数据库的风险。一般来说,同步 SQLite 时间用于与 PostgreSQL(也是同步的)进行比较,异步 SQLite 时间用于与异步 MySQL 引擎进行比较。
测试 1:1000 个 INSERT
创建表 t1(a 整数,b 整数,c VARCHAR(100));
INSERT INTO t1 VALUES(1,13153,'一万三千一百五十三');
INSERT INTO t1 VALUES(2,75560,'七万五千五百六十');
... 省略 995 行
INSERT INTO t1 VALUES(998,66289,'66289');
INSERT INTO t1 VALUES(999,24322,'24322');
INSERT INTO t1 VALUES(1000,94142,'94142');
PostgreSQL: | 4.373 |
MySQL: | 0.114 |
SQLite 2.7.6: | 13.061 |
SQLite 2.7.6(不同步): | 0.223 |
因为它没有中央服务器来协调访问,所以 SQLite 必须关闭并重新打开数据库文件,从而使每个事务的缓存失效。在此测试中,每个 SQL 语句都是一个单独的事务,因此必须打开和关闭数据库文件,并且必须刷新缓存 1000 次。尽管如此,SQLite 的异步版本仍然几乎和 MySQL 一样快。但是,请注意同步版本要慢得多。SQLite 在每个同步事务之后调用fsync()以确保所有数据在继续之前安全地位于磁盘表面。对于同步测试中 13 秒的大部分时间,SQLite 处于空闲状态,等待磁盘 I/O 完成。
测试 2:一个事务中有 25000 个 INSERT
开始;
创建表 t2(a 整数,b 整数,c VARCHAR(100));
INSERT INTO t2 VALUES(1,59672,'五万九千六百七十二');
... 省略 24997 行
INSERT INTO t2 VALUES(24999,89569,'八万九千五百六十九');
INSERT INTO t2 VALUES(25000,94666,'九万四千六百六十六');
犯罪;
PostgreSQL: | 4.900 |
MySQL: | 2.184 |
SQLite 2.7.6: | 0.914 |
SQLite 2.7.6(不同步): | 0.757 |
当所有 INSERT 都放入事务中时,SQLite 不再需要关闭并重新打开数据库或在每个语句之间使其缓存无效。直到最后它也不必执行任何 fsync()。当以这种方式摆脱束缚时,SQLite 比 PostgreSQL 和 MySQL 快得多。
测试 3:将 25000 条 INSERT 插入索引表
开始;
创建表 t3(a 整数,b 整数,c VARCHAR(100));
在 t3(c) 上创建索引 i3;
... 省略 24998 行
INSERT INTO t3 VALUES(24999,88509,'八万八千五百九');
INSERT INTO t3 VALUES(25000,84791,'八万四千七百九十一');
犯罪;
PostgreSQL: | 8.175 |
MySQL: | 3.197 |
SQLite 2.7.6: | 1.555 |
SQLite 2.7.6(不同步): | 1.402 |
有报告称 SQLite 在索引表上的表现不佳。最近添加了此测试以反驳这些谣言。诚然,SQLite 在创建新索引条目时不如其他引擎快(请参阅下面的测试 6),但它的整体速度仍然更好。
测试 4:100 个没有索引的 SELECT
开始;
从 t2 中选择计数 (*)、平均值 (b),其中 b>=0 且 b<1000;
从 t2 中选择计数 (*)、平均值 (b),其中 b>=100 且 b<1100;
... 省略 96 行
SELECT count(*), avg(b) FROM t2 WHERE b>=9800 AND b<10800;
从 t2 中选择计数 (*)、平均值 (b),其中 b>=9900 且 b<10900;
犯罪;
PostgreSQL: | 3.629 |
MySQL: | 2.760 |
SQLite 2.7.6: | 2.494 |
SQLite 2.7.6(不同步): | 2.526 |
此测试在没有索引的 25000 条目表上执行 100 次查询,因此需要全表扫描。在此测试中,以前版本的 SQLite 比 PostgreSQL 和 MySQL 慢,但最近的性能增强提高了它的速度,因此它现在是组中最快的。
测试 5:字符串比较中的 100 个 SELECT
开始;
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%';
犯罪;
PostgreSQL: | 13.409 |
MySQL: | 4.640 |
SQLite 2.7.6: | 3.362 |
SQLite 2.7.6(不同步): | 3.372 |
该测试仍然进行 100 次全表扫描,但它使用字符串比较而不是数字比较。SQLite 在这里比 PostgreSQL 快三倍以上,比 MySQL 快大约 30%。
测试 6:创建索引
在 t2(a) 上创建索引 i2a;
在 t2(b) 上创建索引 i2b;
PostgreSQL: | 0.381 |
MySQL: | 0.318 |
SQLite 2.7.6: | 0.777 |
SQLite 2.7.6(不同步): | 0.659 |
SQLite 在创建新索引时速度较慢。这不是一个大问题(因为不经常创建新索引),但这是正在努力的事情。希望未来版本的 SQLite 能在这方面做得更好。
测试 7:5000 个带索引的 SELECT
从 t2 中选择计数 (*)、平均值 (b),其中 b>=0 且 b<100;
从 t2 中选择计数 (*)、平均值 (b),其中 b>=100 且 b<200;
从 t2 中选择计数 (*)、平均值 (b),其中 b>=200 且 b<300;
...省略了 4994 行
SELECT count(*), avg(b) FROM t2 WHERE b>=499700 AND b<499800;
从 t2 中选择 count(*)、avg(b),其中 b>=499800 且 b<499900;
从 t2 中选择计数 (*)、平均值 (b),其中 b>=499900 且 b<500000;
PostgreSQL: | 4.614 |
MySQL: | 1.270 |
SQLite 2.7.6: | 1.121 |
SQLite 2.7.6(不同步): | 1.162 |
当有索引可供使用时,所有三个数据库引擎都运行得更快。但 SQLite 仍然是最快的。
测试 8:1000 个没有索引的更新
开始;
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;
犯罪;
PostgreSQL: | 1.739 |
MySQL: | 8.410 |
SQLite 2.7.6: | 0.637 |
SQLite 2.7.6(不同步): | 0.638 |
对于这个特定的 UPDATE 测试,MySQL 始终比 PostgreSQL 和 SQLite 慢五到十倍。我不知道为什么。MySQL 通常是一个非常快的引擎。也许这个问题在以后的 MySQL 版本中已经得到解决。
测试 9:25000 个带有索引的更新
开始;
更新 t2 设置 b=468026,其中 a=1;
更新 t2 设置 b=121928,其中 a=2;
...省略了 24996 行
UPDATE t2 SET b=35065 WHERE a=24999;
更新 t2 SET b=347393 其中 a=25000;
犯罪;
PostgreSQL: | 18.797 |
MySQL: | 8.134 |
SQLite 2.7.6: | 3.520 |
SQLite 2.7.6(不同步): | 3.104 |
在最近的 2.7.0 版本中,SQLite 在此测试中的运行速度与 MySQL 大致相同。但最近对 SQLite 的优化使更新速度提高了一倍以上。
测试 10:25000 个带有索引的文本更新
开始;
UPDATE t2 SET c='148382' WHERE a=1;
UPDATE t2 SET c='三十六万六千五百二' WHERE a=2;
... 省略了 24996 行
UPDATE t2 SET c='three83999' WHERE a=24999;
UPDATE t2 SET c='256830' WHERE a=25000;
犯罪;
PostgreSQL: | 48.133 |
MySQL: | 6.982 |
SQLite 2.7.6: | 2.408 |
SQLite 2.7.6(不同步): | 1.725 |
同样,SQLite 2.7.0 版的运行速度与 MySQL 大致相同。但现在 2.7.6 版本比 MySQL 快两倍以上,比 PostgreSQL 快二十多倍。
公平地说,PostgreSQL 在此测试中开始表现不佳。知识渊博的管理员可能能够通过稍微调整和调整服务器来让 PostgreSQL 在这里运行得更快。
测试 11:来自 SELECT 的 INSERT
开始;
插入 t1 从 t2 中选择 b、a、c;
插入 t2 从 t1 中选择 b、a、c;
犯罪;
PostgreSQL: | 61.364 |
MySQL: | 1.537 |
SQLite 2.7.6: | 2.787 |
SQLite 2.7.6(不同步): | 1.599 |
在此测试中,异步 SQLite 仅比 MySQL 慢一点。(MySQL 似乎特别擅长 INSERT...SELECT 语句。)PostgreSQL 引擎仍在颠簸 - 它使用的 61 秒中的大部分时间都花在等待磁盘 I/O 上。
测试 12:没有索引的 DELETE
从 t2 WHERE c LIKE '%50%' 中删除;
PostgreSQL: | 1.509 |
MySQL: | 0.975 |
SQLite 2.7.6: | 4.004 |
SQLite 2.7.6(不同步): | 0.560 |
SQLite 的同步版本是本次测试组中最慢的,但异步版本是最快的。不同之处在于执行 fsync() 所需的额外时间。
测试 13:使用索引删除
从 t2 中删除 a>10 且 a<20000;
PostgreSQL: | 1.316 |
MySQL: | 2.262 |
SQLite 2.7.6: | 2.068 |
SQLite 2.7.6(不同步): | 0.752 |
这个测试很重要,因为它是少数几个 PostgreSQL 比 MySQL 更快的测试之一。然而,异步 SQLite 比其他两个都快。
测试 14:大 DELETE 之后的大 INSERT
插入 t2 从 t1 选择 *;
PostgreSQL: | 13.168 |
MySQL: | 1.815 |
SQLite 2.7.6: | 3.210 |
SQLite 2.7.6(不同步): | 1.485 |
某些旧版本的 SQLite(2.4.0 之前的版本)在执行一系列 DELETE 后跟新的 INSERT 后性能会下降。如该测试所示,问题现已解决。
测试 15:一个大的 DELETE 后面跟着许多小的 INSERT
开始;
从 t1 中删除;
INSERT INTO t1 VALUES(1,10719,'一万七百十九');
... 省略 11997 行
INSERT INTO t1 VALUES(11999,72836,'72836');
INSERT INTO t1 VALUES(12000,64231,'64231');
犯罪;
PostgreSQL: | 4.556 |
MySQL: | 1.704 |
SQLite 2.7.6: | 0.618 |
SQLite 2.7.6(不同步): | 0.406 |
SQLite 非常擅长在事务中执行 INSERT,这可能解释了为什么它在本次测试中比其他数据库快得多。
测试 16:删除表
删除表 t1;
删除表 t2;
删除表 t3;
PostgreSQL: | 0.135 |
MySQL: | 0.015 |
SQLite 2.7.6: | 0.939 |
SQLite 2.7.6(不同步): | 0.254 |
在删除表方面,SQLite 比其他数据库慢。这可能是因为当 SQLite 删除一个表时,它必须遍历并删除处理该表的数据库文件中的记录。另一方面,MySQL 和 PostgreSQL 使用单独的文件来表示每个表,因此它们可以通过删除文件来删除表,这样速度要快得多。
另一方面,删除表并不是一个很常见的操作,所以如果 SQLite 需要更长的时间,那也不是什么大问题。