mongodb比sqlite慢4倍,比csv慢2倍



我正在比较两个dbs的性能,加上csv-数据是100万行乘5列的浮点,大容量插入sqlite/mongodb/csv,在python中完成。

import csv
import sqlite3
import pymongo
N, M = 1000000, 5
data = np.random.rand(N, M)
docs = [{str(j): data[i, j] for j in range(len(data[i]))} for i in range(N)]

写入csv需要6.7秒:

%%time
with open('test.csv', 'w', newline='') as file:
writer = csv.writer(file, delimiter=',')
for i in range(N):
writer.writerow(data[i])

写入sqlite3需要3.6秒:

%%time
con = sqlite3.connect('test.db')
con.execute('create table five(a, b, c, d, e)')
con.executemany('insert into five(a, b, c, d, e) values (?,?,?,?,?)', data)

写入mongo需要14.2秒:

%%time
with pymongo.MongoClient() as client:
start_w = time()
client['warmup']['warmup'].insert_many(docs)
start_w = time()
db = client['test']
coll = db['test']
start = time()
coll.insert_many(docs)
end = time()

我对此还是个新手,但在类似的情况下,mongodb是否会比sqlite慢4倍,比csv慢2倍?它基于mongodb v4.4,带有WiredTiger引擎和python3.8。

我知道mongodb在没有固定模式的情况下表现出色,但当每个文档都有完全相同的键:值对时,就像上面的例子一样,有没有加快大容量插入的方法?

编辑:我测试了在"真实"文字前添加一个热身,作为@D。SM建议。这有帮助,但总的来说,它仍然是最慢的。我的意思是,总的Wall时间23.9秒,(预热14.2+实际插入9.6(。有趣的是,CPU时间总计18.1秒,意味着23.9-18.1=5.8秒是在.insert_many()方法内等待TCP/IO?听起来很多。

在任何情况下,即使我使用预热并忽略IO等待时间,留给实际写入的剩余时间仍然可能大于csv写入,这是一百万次写入((调用!显然csv编写器在缓冲/缓存方面做得更好。我这里出了什么严重的问题吗?

另一个有点相关的问题是:集合文件(/var/lib/mongodb/collection-xxx(的大小似乎不是线性增长的,从第一批开始,每插入一百万次,大小就会增加57MB、15MB、75MB、38MB、45MB、68MB。据我所知,压缩随机数据的大小可能会有所不同,但变化似乎很大。这是意料之中的事吗?

MongoDB客户端连接到后台的服务器。如果你想对插入进行基准测试,一个更准确的测试应该是这样的:

with pymongo.MongoClient() as client:
client['warmup']['warmup'].insert_many(docs)
db = client['test']
coll = db['test']
start = time()
coll.insert_many(docs)
end = time()

请记住,insert_many执行大容量写入,并且大容量写入大小有限制,特别是每次大容量写入只能有1000个命令。如果您要发送100万个插入,那么每次大容量写入可能需要2000个拆分,这些拆分都涉及数据拷贝。与其他批量大小相比,一次插入1000个文档进行测试。

工作测试:


import csv
import sqlite3
import pymongo, random, time
N, M = 1000000, 5
docs = [{'_id':1,'b':2,'c':3,'d':4,'e':5}]*N
i=1
for i in range(len(docs)):
docs[i]=dict(docs[i])
docs[i]['_id'] = i
data=[tuple(doc.values())for doc in docs]
with open('test.csv', 'w', newline='') as file:
writer = csv.writer(file, delimiter=',')
start = time.time()
for i in range(N):
writer.writerow(data[i])
end = time.time()
print('%f' %( end-start))

con = sqlite3.connect('test.db')
con.execute('drop table if exists five')
con.execute('create table five(a, b, c, d, e)')
start = time.time()
con.executemany('insert into five(a, b, c, d, e) values (?,?,?,?,?)', data)

end = time.time()
print('%f' %( end-start))

with pymongo.MongoClient() as client:
client['warmup']['warmup'].delete_many({})
client['test']['test'].delete_many({})
client['warmup']['warmup'].insert_many(docs)
db = client['test']
coll = db['test']
start = time.time()
coll.insert_many(docs)
end = time.time()
print('%f' %( end-start))

结果:

risque% python3 test.py
0.001464
0.002031
0.022351
risque% python3 test.py
0.013875
0.019704
0.153323
risque% python3 test.py
0.147391
0.236540
1.631367
risque% python3 test.py
1.492073
2.063393
16.289790

MongoDB大约是sqlite时间的8倍。

这是意料之中的事吗?可能sqlite和mongodb之间的比较并没有揭示太多,除了sqlite明显更快之外。但是,由于mongodb使用客户端/服务器体系结构,sqlite是一个进程中数据库,因此是意料之中的事,这意味着:

  • 客户端必须序列化要发送到服务器的数据
  • 服务器必须反序列化该数据
  • 然后,服务器必须解析请求并弄清楚该怎么做
  • 服务器需要以可扩展/并发的方式写入数据(sqlite只是我记忆中的并发写入错误(
  • 服务器需要编写回客户端的响应,序列化该响应,并将其写入网络
  • 客户端需要读取响应,反序列化,检查是否成功

5.8秒在.insert_many((方法内等待TCP/IO?听起来很多。

与什么相比-一个不执行任何网络i/o的进程中数据库?

实际写入的剩余时间仍然可能大于csv写入,这是一百万次写入((调用

物理写入调用只是现代数据库进入数据存储的一小部分。

除此之外,这两起案件都没有涉及一百万人。当您向文件写入时,写入在发送到内核之前就由python的标准库进行缓冲——您必须在每行之后使用flush()才能实际产生一百万次写入。在数据库中,类似地逐页执行写入,而不是针对单个文档。

相关内容

  • 没有找到相关文章

最新更新