Klienci MongoDB łączą się z serwerami w tle. Jeśli chcesz porównywać płytki, dokładniejszy test będzie wyglądał następująco:
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()
Należy pamiętać, że insert_many wykonuje zapis zbiorczy i istnieją ograniczenia dotyczące rozmiarów zapisu zbiorczego, w szczególności może być tylko 1000 poleceń na zapis zbiorczy. Jeśli wysyłasz milion wstawek, możesz patrzeć na 2000 podziałów na zapis zbiorczy, z których wszystkie obejmują kopie danych. Przetestuj wstawianie 1000 dokumentów jednocześnie w porównaniu z innymi rozmiarami partii.
Test pracy:
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))
Wyniki:
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 to około 8x czas sqlite.
Czy tego się oczekuje? Być może. Porównanie sqlite i mongodb nie pokazuje wiele poza tym, że sqlite jest znacznie szybsze. Ale oczywiście to jest oczekiwane, ponieważ mongodb wykorzystuje architekturę klient/serwer, a sqlite jest wewnętrzną bazą danych, co oznacza:
- Klient musi serializować dane do wysłania na serwer
- Serwer musi deserializować te dane
- Serwer musi następnie przeanalizować żądanie i dowiedzieć się, co zrobić
- Serwer musi zapisywać dane w sposób skalowalny/współbieżny (sqlite po prostu błędy z współbieżnymi błędami zapisu z tego, co pamiętam)
- Serwer musi skomponować odpowiedź z powrotem do klienta, zserializować tę odpowiedź, zapisać ją w sieci
- Klient musi przeczytać odpowiedź, zdeserializować ją, sprawdzić, czy zakończyła się sukcesem
W porównaniu z czym — wewnątrzprocesowa baza danych, która nie wykonuje żadnego we/wy sieciowe?
Fizyczne wywołania zapisu stanowią niewielką część tego, co trafia do przechowywania danych przez nowoczesną bazę danych.
Poza tym żadna sprawa nie dotyczy miliona z nich. Kiedy piszesz do pliku, zapisy są buforowane przez standardową bibliotekę Pythona, zanim zostaną wysłane do jądra - musisz użyć flush()
po każdej linii, aby faktycznie wyprodukować milion zapisów. W bazie danych zapisy są podobnie wykonywane strona po stronie, a nie dla poszczególnych dokumentów.