一、引言 在很多项目中,经常会碰到这样的需求,需要对大量数据进行快速存储、查询、删除等操作,特别是在一些针对诸如运营商、银行等大型企业的应用中,这些 需求尤为常见。比如智能网中的大量在线并发用户的数据管理、软交换平台中的在线信息交互、宽带 /3G 等数据网中在线用户行为记录等等。 针对这些情形,我们通常需要选择高性能的 ..

内存数据库FastDB和SQLite性能测评

本贴最后更新于 2200 天前,其中的信息可能已经水流花落

一、引言

在很多项目中,经常会碰到这样的需求,需要对大量数据进行快速存储、查询、删除等操作,特别是在一些针对诸如运营商、银行等大型企业的应用中,这些 需求尤为常见。比如智能网中的大量在线并发用户的数据管理、软交换平台中的在线信息交互、宽带 /3G 等数据网中在线用户行为记录等等。

针对这些情形,我们通常需要选择高性能的数据库产品,而且通常需要使用内存数据库,顾名思义,内存数据库指的是所有的数据访问控制都在内存中进行, 这是与磁盘数据库相对而言的,磁盘数据库虽然也有一定的缓存机制,但都不能避免从外设到内存的交换,而这种交换过程对性能的损耗是致命的,目前主流数据库 如 SYBASE、ORACLE 等都有这种缓存机制,如将特定表绑定一定的缓存,从而在一定程度上改善数据吞吐性能。而内存数据库几乎可以完全避免这种内外 存数据交换的发生,特别是在物理内存足够大的设备上尤其如此,通常这种数据库也被称为主存数据库 (Main Memory DataBase, MMDB)。

二、主存数据库比较

目前比较知名的商业内存数据库有,ORACLE 的 TimesTen,MCObject 的 eXtremeDB、韩国的 Altibase 等,这些数据库 产品性能都非常的强劲,当然价格也相当的强劲,在非特大型系统建设时,通常让人望而却步。于是退而求其次,免费开源内存数据库给了我们第二种选择。 Berkeley DB,SQLite,MonetDB,FastDB,H2 等,不一而足。本文主要针对 SQLite 和 FastDB 进行性能测评。

2.1 测试准备

首先,笔者通过对评测数据的调研发现,通常认为,BDB 性能不如 SQLite,参考"免费的实时数据库,我们该选谁?---BerkeleyDB 与 SQLite 评测对比"

上文中还提到,"据说 FastDB 很快,但数据库大小不能大于物理内存...",于是笔者对 FastDB 产生了兴趣,从 FastDB 作者的网站看到关于 这点的介绍,并不是说数据库大小不能大于物理内存,而是说数据库大小超过物理内存时,性能与不超过时相比会有一定的降低 (降低幅度未作说明,估计是不推荐 使用)。幸运地是,目前物理内存实在说不上贵,服务器内存在 10G 之上都是很正常的事情了。因此可以根据具体项目数据量需求来确定是否能使用 FastDB,比如并不是所有的表都需要放在内存中。下面即将描述的测试表明,一旦使用 FastDB,其性能在免费 MMDB 产品中绝对可执牛耳。由于已经 有人对 BDB 和 SQLite 进行过比较,因此下面仅将 FastDB 与其中的优胜者 SQLite 进行性能测评。SQLite 采用内存模式,即打开数据库使使 用 ":memory:" 参数,此时 SQLite 不产生数据库文件,所有操作都在内存中,这一点需要特殊说明,与之不同的是,FastDB 有两种模式,磁盘 模式和无盘模式,前者会产生磁盘文件,后者则与 SQLite 的内存模式相同。

说是测评,其实过程也很简单,无非是设计测试 CASE,编写测试 CODE,输出测试 RESULT,最后做出结论。通常我们认为带索引的插入耗时相对 于查询和删除来说比较长,因此首先来看插入性能。采用一个简单的表来完成接下来的所有测试,表中仅包含两个字段,INTEGER intKey,和 VARCHAR strKey。测试平台为 Window7 32bit 系统 (Evaluation Copy 7127),编译器 VC6 SP6。在 DELL INSPIRON 640m 上运行,CPU 为 Intel Core 2 CPU T5500 @ 1.66GHZ,内存 2.5G。

对 FastDB(采用磁盘模式),表结构的定义如下:

class _TestTable 

public: 
    db_int8 intKey; 
    char const* strKey; 
    TYPE_DESCRIPTOR((KEY(intKey, INDEXED), KEY(strKey, INDEXED))); 
};

REGISTER(_TestTable);

对 SQLite,建表 SQL 如下:

CREATE TABLE [_TestTable] ([intKey] INTEGER  NOT NULL PRIMARY KEY, [strKey] VARCHAR(50)  NULL)

2.2 不同事务模式下的插入性能比较

2.2.1 FastDB 磁盘模式

我们首先按照批量事务处理的模式将 intKey 从 1 到 nRecords(记录条数),并指定相应的 strKey,分别调用相应的接口 (均为原始 API) 插入到两张表中,这里的批量事务处理模式指的是,比如插入 10000 条记录,插第一条之前开始事务,最后一条之后结束事务。此时在插入不同数目记 录时的表现分别如下 (一万条、十万条、72 万条、一百万条):

批量事务提交:

E:\intrest\FastDB\PerfTest\Debug>PerfTest.exe 
[FASTDB] Elapsed time for inserting 10000 record: 63 ms 
[SQLITE] Elapsed time for inserting 10000 record: 639 ms

E:\intrest\FastDB\PerfTest\Debug>del *.fdb (清除测试生成数据,重新测试,下同。)

E:\intrest\FastDB\PerfTest\Debug>PerfTest.exe 
[FASTDB] Elapsed time for inserting 100000 record: 1186 ms 
[SQLITE] Elapsed time for inserting 100000 record: 6318 ms

E:\intrest\FastDB\PerfTest\Debug>del *.fdb

E:\intrest\FastDB\PerfTest\Debug>PerfTest.exe 
[FASTDB] Elapsed time for inserting 7200000 record: 152460 ms 
[SQLITE] Elapsed time for inserting 7200000 record: 560121 ms

E:\intrest\FastDB\PerfTest\Debug>PerfTest.exe 
[FASTDB] Elapsed time for inserting 1000000 record: 15522 ms 
[SQLITE] Elapsed time for inserting 1000000 record: 67423 ms

从上我们可以看出,在批量事务模式下,FastDB 比 SQLite 的插入性能提高了 3-10 倍。但是在很多情况下,我们可能会需要逐条逐条的事务提交,下面给出了逐条事务模式的测试结果:

E:\intrest\FastDB\PerfTest\Debug>PerfTest.exe 
[FASTDB] Elapsed time for inserting 10000 record: 57315 ms(这个太恐怖了,不调整的话没法使用) 
[SQLITE] Elapsed time for inserting 10000 record: 780 ms

E:\intrest\FastDB\PerfTest\Debug>PerfTest.exe (SQLITE 显式分条事务) 
[FASTDB] Elapsed time for inserting 10000 record: 59967 ms 
[SQLITE] Elapsed time for inserting 10000 record: 1154 ms

从上我们可以看出,FastDB 在这种情形下的性能急遽降低,降到一个几乎不能接收的水平。经过对 FastDB 的源代码分析 (开源的好处体现出来 了),发现 FastDB 在每次事务提交时,都会将变更的数据内容同步到磁盘文件中(这是因为我们采用了磁盘模式),因此造成性能的显著降低。

直观上看,解决 FastDB 的这个问题有两种办法,一是避免每次事务提交时同步到磁盘,因为在这种应用中,这种同步操作并不需要实时进行,通常每隔 一段时间同步一次就可以了 (比如 1S、1Min、等根据具体项目的可靠性需要);二是使用前面提到的 FastDB 无盘 (DISKLESS) 模式。

我们首先来看第一种方案,通过 SEARCH FastDB 文档 (文档和社区是 FastDB 的一个软肋),我们发现作者已经考虑到了这个问题,FastDB 为数据库提供了 precommit 的接口,用 于完成除 sync 到磁盘文件外的所有事物操作,如释放 mutex 资源等。同时提供了 backup 接口,用来完成内存数据到磁盘文件的备份,甚至支持打开数 据库时同时指定定时备份到磁盘文件的间隔。这样一来,每次事务提交的效率理论上会得到大大提高,并且通过定时备份机制可以保证数据的可靠性。我们来看使用 precommit 进行逐条事务提交时 FastDB 的表现:

E:\intrest\FastDB\PerfTest\Debug>PerfTest(使用 precommit 逐条提交事务) 
[FASTDB] Elapsed time for inserting 10000 record: 62 ms 
[SQLITE] Elapsed time for inserting 10000 record: 1170 ms

E:\intrest\FastDB\PerfTest\Debug>PerfTest 
[FASTDB] Elapsed time for inserting 100000 record: 1170 ms 
[SQLITE] Elapsed time for inserting 100000 record: 11747 ms

E:\intrest\FastDB\PerfTest\Debug>PerfTest 
[FASTDB] Elapsed time for inserting 1000000 record: 8081 ms 
[SQLITE] Elapsed time for inserting 1000000 record: 125768 ms

从上可以看出,在逐条事务模式下,通过使用 precommit 技术,FastDB 性能比 SQLite 提高了 10 倍左右。当然也许有读者怀疑加了备份 机制之后的性能,确实笔者没有进行这项测试,但是,需要注意的是,FastDB 在数据库关闭时会强制 sync 到磁盘文件,但 SQLite 没有这种功能,同 时,在进行这项测试时,两种数据库都没有定时备份机制,因此该比较是公平的。

2.2.2 FastDB 无盘模式

再来看第二种方案,FastDB 采用无盘 (通过编译选项控制生成 DISKLESS 版本) 模式,此时 FastDB 初始化一段共享内存 (shmat or mmap),这个初始大小通常很大,并且运行期不能扩展(无盘模式的劣势)。我们将初始共享内存设置为 1G,得到的测试结果如下:

E:\intrest\FastDB\PerfTest\Debug>PerfTest.exe 
[FASTDB] Elapsed time for inserting 100000 record: 624 ms (批量事务提交) 
[SQLITE] Elapsed time for inserting 100000 record: 11544 ms

E:\intrest\FastDB\PerfTest\Debug>PerfTest.exe 
[FASTDB] Elapsed time for inserting 100000 record: 7410 ms (逐条事务提交) 
[SQLITE] Elapsed time for inserting 100000 record: 11560 ms

E:\intrest\FastDB\PerfTest\Debug>PerfTest.exe 
[FASTDB] Elapsed time for inserting 1000000 record: 134660 ms 
[SQLITE] Elapsed time for inserting 1000000 record: 120167 ms

E:\intrest\FastDB\PerfTest\Debug>PerfTest.exe 
[FASTDB] Elapsed time for inserting 250000 record: 23666 ms 
[SQLITE] Elapsed time for inserting 250000 record: 29110 ms

从上我们可以看出,无盘模式在大数据量下的表现与 SQLite 相近,这一点不是很好理解,需要研究 DISKLESS 的设计模式,理论上应该与 precommit 模式性能相近。但是实践是检验真理的唯一标准。我们可以看出,磁盘模式的 precommit 方式性能表现卓越,不管从横向还是纵向来 看。

2.3 查询性能比较

下面的比较都使用磁盘模式的 precommit 方式,再来看索引查询的性能表现,测试时都是先插入十万条数据后,再分别对该十万条数据进行查询,需 要注意的是我们同时对 FastDB 是否增加 HASH 索引的性能进行了横向测评,FastDB 增加 HASH 索引很简单,通过修改 TYPE- DESCRIPTOR 来完成,上面的 class 中改为 TYPE_DESCRIPTOR((KEY(intKey, INDEXED), KEY(strKey, INDEXED))); 即为 intKey 增加了 Hash 索引。

E:\intrest\FastDB\PerfTest\Debug>perftest (FASTDB 哈希索引) 
[FASTDB] Elapsed time for inserting 100000 record: 624 ms 
[FASTDB] Elapsed time for 100000 index searches: 328 ms 
[SQLITE] Elapsed time for inserting 100000 record: 10312 ms 
[SQLITE] Elapsed time for 100000 index searches: 10935 ms

E:\intrest\FastDB\PerfTest\Debug>perftest(FASTDB 非哈希索引) 
[FASTDB] Elapsed time for inserting 100000 record: 577 ms 
[FASTDB] Elapsed time for 100000 index searches: 515 ms 
[SQLITE] Elapsed time for inserting 100000 record: 10343 ms 
[SQLITE] Elapsed time for 100000 index searches: 9532 ms

从测试结果可以看出,查询十万条索引记录的效率,FastDB 要比 SQLite 快 20 倍左右,并且在增加 HASH 索引后能够得到进一步的改善。

2.4 删除性能比较及综合表现

最后,我们在测试删除效率时,同时综合来看 FastDB 与 SQLite 之间插入、查询、删除的性能表现:

插入、查询、删除综合比较:

E:\intrest\FastDB\PerfTest\Debug>perftest(批量删除,FASTDB.removeall(),SQLITE.delete*) 
[FASTDB] Elapsed time for inserting 100000 record: 608 ms 
[FASTDB] Elapsed time for 100000 index searches: 687 ms 
[FASTDB] Elapsed time for deleting all 100000 records: 16 ms 
[SQLITE] Elapsed time for inserting 100000 record: 11107 ms 
[SQLITE] Elapsed time for 100000 index searches: 10062 ms 
[SQLITE] Elapsed time for deleting all 100000 records: 16 ms

E:\intrest\FastDB\PerfTest\Debug>perftest(逐条删除) 
[FASTDB] Elapsed time for inserting 100000 record: 593 ms 
[FASTDB] Elapsed time for 100000 index searches: 562 ms 
[FASTDB] Elapsed time for deleting all 100000 records one by one: 905 ms 
[SQLITE] Elapsed time for inserting 100000 record: 10406 ms 
[SQLITE] Elapsed time for 100000 index searches: 10249 ms 
[SQLITE] Elapsed time for deleting all 100000 records one by one: 8923 ms

从上可以看出,就删除效率而言,批量删除的速度二者相近,而逐条删除时,十万条记录的删除累积,FastDB 比 SQLite 快了 10 倍左右。

 

2.5 总结

优点:FastDB 磁盘模式下,采用 precommit 方式,性能远远优于 SQLite,并且 FastDB 提供了完善的备份恢复机制,能够保证数据 安全。FastDB 的无盘模式在小数据量时表现优越,并且不会产生磁盘数据文件,也不能加载已经保存的数据库文件,看起来更像是针对嵌入式设备 (如智能手 机、PDA 等) 开发的,对于这种场景可以考虑使用无盘模式。

缺点:FastDB 目前能够 SEARCH 到的比较著名的应用是 PingTel 公司的开源统一通信产品 SIPX,该产品采用的是 FastDB 的磁盘模 式。这可能多少与 FastDB 的完全授权模式有关,而 SQLite 采用的是 GPL 的不允许闭源的商业发布。当然主要还是社区的不成熟,这从 Google Trends 的搜索结果也能看出。社区的不成熟会带来学习成本的增加,这一点在选型时也需要考虑。

  • 数据库

    据说 99% 的性能瓶颈都在数据库。

    234 引用 • 525 回帖
回帖   
请输入回帖内容...