Closed pat1 closed 9 months ago
La issue non è assegnata a me, ma ho provato a riprodurlo su un'immagine Rocky Linux 8 con moncic-ci e non riesco, perché arriva in fondo (ci mette il suo tempo ma ci arriva):
$ monci shell rocky8
[root@mc-folusa ~]# dnf install -qy wget dballe postgresql-server
[root@mc-folusa ~]# /usr/bin/postgresql-setup --initdb
[root@mc-folusa ~]# su - postgres
[postgres@mc-folusa ~]$ createdb report_fixed
[postgres@mc-folusa ~]$ dbadb wipe --dsn=postgresql:///report_fixed
[postgres@mc-folusa ~]$ wget https://github.com/ARPA-SIMC/dballe/files/13588478/bufr.zip && unzip bufr.zip
[postgres@mc-folusa ~]$ time python3 test.py
real 8m32.439s
user 0m32.450s
sys 0m3.310s
La butto lì: hai provato ad aggiornare postgres e dballe?
[root@mc-folusa ~]# rpm -qi postgresql-server | head -n3
Name : postgresql-server
Version : 10.23
Release : 2.module+el8.9.0+1500+e42a8b96
[root@mc-folusa ~]# rpm -qi dballe | head -n3
Name : dballe
Version : 9.5
Release : 1.el8
@spanezz spero che possa essere utile
unica differenza: rpm -qi postgresql-server | head -n3 Name : postgresql-server Version : 12.15 Release : 3.module+el8.9.0+1331+6f33d496
In attesa di replica del problema e di condivisione di accesso al server problematico
replicato sulla macchina di test fare riferimento alla cartella dballe_issue_282 nella home di root
Ho guardato al problema nella macchina di test.
Una differenza fondamentale nei due comandi è che python ha overwrite=True, update_station=True, import_attributes=True
, e quindi andrebbe confrontato con dbadb import .. --full-pseudoana --overwrite
invece che con dbadb import
.
Ho aggiunto un po' di progress reporting a test.py
(lo trovi come test1.py
nella macchina di test):
import os,io
import dballe
import time
dsn="postgresql://rmap:rmap@localhost/test"
#dsn="sqlite:troppograndi.sqlite"
with open("troppograndi","rb") as myfile:
totalbody=myfile.read()
totalbodyfile = io.BytesIO(totalbody)
# Connect to the database
db = dballe.DB.connect(dsn)
importer = dballe.Importer("BUFR")
last_time = time.time()
# Start a transaction
with db.transaction() as tr:
with importer.from_file(totalbodyfile) as f:
for idx, dballemessage in enumerate(f):
if idx % 100 == 0:
current_time = time.time()
mps = 100 / (current_time - last_time)
print(f"Import message #{idx}/142026 ({mps:.2f} mps)")
last_time = current_time
try:
tr.import_messages(dballemessage,overwrite=True, update_station=True,import_attributes=True)
except KeyError:
self._logging.error("Message was rejected importing in DB: not all metadata defined! ")
Facendolo girare si vede che il conto dei messaggi al secondo cala man mano che procede lo script. Similmente, se lanci:
pv troppograndi | time dbadb import --dsn="postgresql://rmap:rmap@localhost/test" --full-pseudoana --overwrite
vedi che i kb/s di messaggi processati man mano cala, e l'ETA aumenta.
Del resto, usando update_station
stai chiedendo a dballe, per ogni singolo messaggio importato, di riscrivere tutti i dati stazione: l'idea per la gestione dei dati stazione era che il primo messaggio importato per una stazione li scrive, e al limite si possono importare dei messaggi coi dati piú aggiornati alla bisogna per aggiornarli. Ci sta che usare --full-pseudoana
o update_station=True
per importare un pacchetto da 140mila messaggi dia delle performance inaccettabili.
Però sí, aggiungendo un report sul progress non è tanto piantato, quanto è un caso d'uso che non scala
Come riportato in questa issue sopra queste sono le performance con sqlite:
dbadb wipe --url=sqlite:troppograndi.sqlite
time python3 test.py
real 0m12,912s
user 0m12,815s
sys 0m0,037s
dovendo usare overwrite=True, update_station=True, import_attributes=True l'unica soluzione è utilizzare sqlite o è possibile avere in qualche modo performance simili in postgresql?
Non ho idea di come poter avere performance simili con postgresql: la struttura dei DB è la stessa.
Puoi provare a dividere il file di input in transazioni di un migliaio di BUFR l'una per vedere se migliora qualcosa?
i dati non li produco io, il python che uso per fare l'importazione è quello sopra a parte la lettura da file in quanto i dati non risiedono in un file. C'è un modo per farlo in python ?
Con qualcosa tipo https://docs.python.org/3.12/library/itertools.html#itertools.batched (da python 3.12) o un'equivalente implementazione manuale
ma scusa con itertools come faccio a non troncare a mezzo un bufr ? Se lo spezzo in 10 parti rompo 9 bufr. Oltre al fatto che ogni importazione mi darebbe errore ...
Puoi dividere in gruppi l'iterazione di for dballemessage in f:
che itera messaggio per messaggio, e aprire una transazione per gruppo invece della transazione all'esterno
una transazione per messaggio:
time python3 test.py
real 6m47,500s
user 0m22,844s
sys 0m29,945s
una transazione per 10 messaggi:
time python3 test.py
real 2m13,508s
user 0m8,995s
sys 0m10,856s
una transazione per 100 messaggi:
time python3 test.py
real 1m29,868s
user 0m6,518s
sys 0m6,011s
una transazione per 1000 messaggi:
time python3 test.py
real 1m59,135s
user 0m6,362s
sys 0m7,020s
sqlite continua ad avere performance molto ma molto migliori. una transazione per messaggio:
time python3 single.py
real 0m35,258s
user 0m32,130s
sys 0m2,932s
una transazione ogni 100 messaggi:
time python3 test.py
real 0m12,980s
user 0m4,433s
sys 0m0,220s
Questa cosa mi lascia qualche dubbio, ma se il mio dubbio è considerato effimero si può chiudere la issue.
la risposta per postgres credo sia qui: https://stackoverflow.com/questions/60166976/why-is-postgres-transaction-block-so-much-slower-and-how-to-solve
rimane poco chiaro come mai sqlite invece non ha questo problema.
Perché sqlite è una bestia completamente diversa da postgresql, fatta per gestire situazioni diverse.
In particolare, sqlite non deve gestire scritture concorrenti come invece deve fare postgresql, e quindi può prendere scorciatoie che postgres non si può permettere
test bufr are attached bufr.zip with sqlite:
with posgres:
test.py