MongoDB-klienter opretter forbindelse til serverne i baggrunden. Hvis du vil benchmarke inserts, ville en mere nøjagtig test være noget som denne:
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()
Husk, at insert_many udfører en masseskrivning, og der er begrænsninger for masseskrivningsstørrelser, især kan der kun være 1000 kommandoer pr. masseskrivning. Hvis du sender 1 million indstik, kan du se på 2000 opdelinger pr. bulkskrivning, som alle involverer datakopier. Test at indsætte 1000 dokumenter ad gangen i forhold til andre batchstørrelser.
Arbejdstest:
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))
Resultater:
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 er omkring 8 gange så meget som sqlite-tiden.
Er dette forventet? Måske. Sammenligningen mellem sqlite og mongodb afslører ikke meget udover, at sqlite er markant hurtigere. Men naturligvis dette forventes, da mongodb bruger en klient/server-arkitektur, og sqlite er en igangværende database, hvilket betyder:
- Klienten skal serialisere dataene for at sende til serveren
- Serveren skal deserialisere disse data
- Serveren skal derefter analysere anmodningen og finde ud af, hvad den skal gøre
- Serveren skal skrive dataene på en skalerbar/samtidig måde (sqlite fejler simpelthen fejl med samtidige skrivefejl fra, hvad jeg husker af det)
- Serveren skal komponere et svar tilbage til klienten, serialisere det svar, skrive det til netværket
- Kunden skal læse svaret, deserialisere, kontrollere det for succes
Sammenlignet med hvad - en igangværende database, der ikke gør noget netværks-i/o?
De fysiske skriveopkald er en lille del af det, der går til datalagring af en moderne database.
Udover det involverer ingen af sagerne en million af dem. Når du skriver til fil, bufres skrivningerne af pythons standardbibliotek, før de overhovedet sendes til kernen - du skal bruge flush()
efter hver linje for faktisk at producere en million skriverier. I en database udføres skrivningerne på samme måde side for side og ikke for individuelle dokumenter.