BerkeleyDB的使用上有许多需要注意的地方, 尤其对于想要提高性能而言. 由于许多使用BerkeleyDB都是参照网上的例子, 所以一般用的都比较简单, 许多性能优化策略没有讨论过.

1 平衡数据持久性和性能
许多应用其实并不需要数据完全不丢失, 偶尔丢失一点点其实没有多大影响. 但是有不少这类的应用在使用事务时, 指定的却是txn_sync(相当于innodb的innodb_flush_log_at_trx_commit=1的方式), 性能自然底下. 应当合理分析数据部分丢失的影响,在奔溃后可以丢失部分数据的场合, 可以合理的选择持久化的级别来大幅度改善性能. 对于崩溃后允许部分数据丢失的场合, 可以合理的设置log buffer(DB_ENV.set_lg_bsize), 并且使用DB_TXN_NOSYNC(相当于innodb_flush_log_at_trx_commit=0)或者DB_TXN_WRITE_NOSYNC(innodb_flush_log_at_trx_commit=2)的事务, 二者区别在于, 前者在程序崩溃时, 数据丢失, 后者在程序崩溃时数据还在, 只是在操作系统关闭时, 数据才会丢失.

2 合理使用事务隔离级别
默认使用事务时, 是serializable的级别, 但是serializable的级别遵循严格的two-phase locking协议, 在lock上持有较长时间.哪怕是read-lock,哪怕是以后不再访问. 但实际上, 很多应用程序并没有如此高的一致性要求, 不需要如此高的隔离级别. 比如使用DBCursor进行顺序扫描, 扫描过元素后,将不会访问该元素, 完全没必要一直持有读锁. 而对于某些插入就不变(不修改不删除)的确定性数据而言, 也没有必要等到所有操作结束后才释放写锁, 完全可以提前释放, 至少可以让读程序提前访问. 所以应当分析应用对数据一致性的要求,合理选择隔离级别. 对于游标的例子而言, 可以选择read_committed, 游标只读取提交的改动, 读取完一页后,可以释放该页上的读锁. 对于第二个例子而言, 甚至可以选择read_uncommitted.

3 合理的数据访问顺序
一般应用性能瓶颈最大的在cache, 所以提高cache的命中率至关重要. 许多应用按完全随机的顺序访问数据, 当数据很大时(大于cache), cache命中率可能很低. 但实际上, 许多应用在短时间内访问并不完全要求按时间排序, 尽管长时间看是按时间排序的. 这种情况下, 可以把一个时间段内的访问按key排序, 而后向berkeleydb发送访问请求, 只要排序方式具有稳定性, 能保证同key操作的时序即可. 使用这种方式可以在应用中大幅提高性能, 这也类似于LSM中的处理方式, 以及innodb的插入缓冲, 只是要自己实现merge的过程.

4 数据建立
在用其他数据源的数据来初始化BerkeleyDB时, 主要有以下几个方面可以考虑:
* 外部数据源先按BerkeleyDB的Key排序,而后发送操作请求给BerkeleyDB
* 对于有索引的,先把数据导入到primary table而后在建立索引(DB_CREATE方式), 通常比建立索引在导入数据快得多

5 一些近些版本新功能中可以考虑的地方
* 使用partition特性将同一个数据库的数据分布在不同的磁盘, 将data数据和log数据存放在不同的磁盘, 使用多盘的并行操作
* 大块数据存储时, 考虑使用BLOB方式进行操作
* 查询完全以secondary indexes进行时, 考虑使用DB_HEAP作为primary database的access method, 在其上建立相应的二级索引.

OK , 先到这里 ....

09-01 03:05