LMDB/Python vs BerkeleyDB/Python随机键查询:如何提升LMDB速度
LMDB查询速度远慢于BerkeleyDB的问题解决
问题背景
之前用BerkeleyDB存储事件日志,迁移到LMDB后发现,在13k+条记录的场景下,单值查询比BerkeleyDB慢约1秒每条。BerkeleyDB已存储70GB+(约3000万条记录)的数据,处理这些事件耗时超1小时,原本以为切换LMDB能提速,结果反而变慢。我的业务逻辑是写入事件前先检查是否存在重复。
环境初始化代码
BerkeleyDB初始化
env = db.DBEnv() env.open(db_folder, db.DB_INIT_MPOOL | db.DB_CREATE | db.DB_INIT_LOG | db.DB_INIT_TXN | db.DB_RECOVER, 0) database = db.DB(env)
LMDB初始化
env = lmdb.open(db_folder, map_size=100000000000, max_dbs=4, readahead=False) database = env.open_db('events'.encode())
查询与写入代码对比
BerkeleyDB版本
if event['eId'].encode('utf-8') in database: duplicate_count += 1 else: try: txn = env.txn_begin(None) database[event['eId'].encode('utf-8')] = json.dumps(event).encode('utf-8') except: if txn is not None: txn.abort() txn = None raise else: txn.commit() txn = None event_count += 1
LMDB原实现(慢版本)
with env.begin(buffers=True, db=database) as txn: if (txn.get(event['eId'].encode()) is not None): dup_event_count += 1 else: txn.put(event['eId'].encode(), json.dumps(event).encode('utf-8')) event_count += 1
解决方案
速度慢的核心原因是LMDB事务创建开销过大——原代码在循环内每次都新建事务(with env.begin放在循环内部),而BerkeleyDB的查询直接在数据库对象上执行,仅在写入时才创建事务。
将事务初始化移到循环外部,复用同一个事务处理所有查询和写入操作,就能大幅提升性能。示例对比代码:
@case('复用事务查询') def test(): with env.begin() as txn: for word in words: txn.get(word) return len(words) @case('每次查询新建事务') def test(): for word in words: with env.begin() as txn: txn.get(word) return len(words)
第一个用例把with env.begin放在循环外,复用单个事务,速度会远快于第二个每次循环都创建新事务的用例。
内容的提问来源于stack exchange,提问作者mark
相关产品推荐
相关产品推荐

