Python DBM真的很快吗?

时间:2011-10-12 09:56:37

标签: python nosql database dbm

我认为Python的原生DBM应该比NOSQL数据库(例如Tokyo Cabinet,MongoDB等)快得多(因为Python DBM具有较少的功能和选项;即更简单的系统)。我用一个非常简单的写/读示例测试

#!/usr/bin/python
import time
t = time.time()
import anydbm
count = 0
while (count < 1000):
 db = anydbm.open("dbm2", "c")
 db["1"] = "something"
 db.close()
 db = anydbm.open("dbm", "r")
 print "dict['Name']: ", db['1'];
 print "%.3f" % (time.time()-t)
 db.close()
 count = count + 1

读/写:1.3s 阅读:0.3秒 写:1.0s

MongoDb的这些值至少快5倍。它真的是Python DBM性能吗?

2 个答案:

答案 0 :(得分:14)

Python没有内置的DBM实现。它的DBM功能基于各种DBM风格的第三方库,如AnyDBM,Berkeley DBM和GNU DBM。

Python的字典实现对于键值存储来说非常快,但不是持久的。如果您需要高性能的运行时键值查找,您可能会更好地找到字典 - 您可以使用cpickle或shelve之类的东西来管理持久性。如果启动时间对您很重要(如果您正在修改数据,终止) - 比运行时访问速度更重要 - 那么像DBM这样的东西会更好。

在您的评估中,作为主循环的一部分,您既包括dbm open调用,也包括数组查找。在查找之前打开DBM来存储一个值并关闭并重新打开是一个非常不切实际的用例,并且您看到了以这种方式管理持久性数据存储时的典型缓慢性能(它是非常低效。)

根据您的要求,如果您需要快速查找并且不太关心启动时间,DBM可能是一个解决方案 - 但要对其进行基准测试,只需在循环中包含写入和读取!类似下面的内容可能是合适的:

import anydbm
from random import random
import time

# open DBM outside of the timed loops
db = anydbm.open("dbm2", "c")

max_records = 100000

# only time read and write operations
t = time.time()

# create some records
for i in range(max_records):
  db[str(i)] = 'x'

# do a some random reads
for i in range(max_records):
  x = db[str(int(random() * max_records))]

time_taken = time.time() - t
print "Took %0.3f seconds, %0.5f microseconds / record" % (time_taken, (time_taken * 1000000) / max_records)

db.close()

答案 1 :(得分:1)

在python3中,嵌入式密钥库足够快。以

为例,以本机字典为基准
for k in random.choices(auList,k=100000000):
    a=auDict[k]
CPU times: user 1min 6s, sys: 1.07 s, total: **1min 7s**

GDBM对此并不感到遗憾

%%time
with db.open("AuDictJson.gdbm",'r') as d:
    for k in random.choices(auList,k=100000000):   
        a=d[str(k)]   
CPU times: user 2min 44s, sys: 1.31 s, total: **2min 45s**

甚至是一个专业的预编译表,作为json序列化列表的关键,也几乎可以做到。

%%time
d = keyvi.Dictionary("AuDictJson.keyvi")
for k in random.choices(auList,k=100000000):   
    a=d[str(k)].GetValue()
CPU times: user 7min 45s, sys: 1.48 s, total: 7min 47s

通常,嵌入式套接字数据库(尤其是只读且为单个用户的嵌入式数据库)应该总是赢得外部数据库,因为套接字和信号灯访问资源的开销很大。另一方面,如果您的程序是具有某些外部I / O瓶颈的服务(例如,您正在编写Web服务),则访问资源的开销可能不重要。

说,如果外部数据库提供了额外的服务,则可以看到使用它们的一些优势。对于Redis,请考虑集合的并集。

%%time
for j in range(1000):
    k=r.sunion(('s'+str(k) for k in random.choices(auList,k=10000)))  
CPU times: user 2min 24s, sys: 758 ms, total: 2min 25s

与gbm相同的任务处于相同的数量级。尽管redis的速度仍然慢了5倍,但还不至于使其丢弃

%%time 
with db.open("AuDictPSV.gdbm",'r') as d:
    for j in range(1000):
        a=set()
        for k in random.choices(auList,k=10000):
            a.update(d[str(k)].split(b'|'))
CPU times: user 33.6 s, sys: 3.5 ms, total: 33.6 s

在这种情况下,通过使用Redis,您可以获得数据库的完整功能,而不仅仅是简单的数据存储。当然,与很多客户一样,与很多单一资源相比,与嵌入式资源相比,它的性能将很差。

关于gdbm竞争,查尔斯·莱弗(Charles Leifer)的2014 benchmark表明,它的性能可以胜过KyotoCabinet,因为仍然可以书写,而且可以将LevelDB和RocksDB视为高级替代方案。