Come interrogare efficacemente il database con lo stesso programma milioni di volte

0

Ho ottenuto un software proprietario (qualcosa come un sistema DMS) per elaborare i documenti nel file system. Il software fornisce API molto limitate per manipolare il contenuto dei documenti in DMS ma consente di chiamare la riga di comando durante l'elaborazione del documento. Ho in programma di scrivere un programma python per interrogare il database ed estrarre il record del database corrispondente del documento per arricchire il contenuto in DMS.

Tuttavia, quando il software elabora ogni singolo documento, chiamerà il programma python una volta. Se ci sono milioni di documenti in fase di elaborazione, chiamerà il programma python milioni di volte. È efficace connettere e chiudere la connessione al database ogni volta che elabora un documento? C'è un approccio migliore per recuperare il record nel database?

Codice di esempio del programma python

import MySQLdb
import sys

filename = str(sys.argv[1])

db = MySQLdb.connect("localhost","testuser","test123","TESTDB" )
cursor = db.cursor()
cursor.execute("SELECT * from example_table where filename='" + filename + "'")
data = cursor.fetchone()
db.close()
sys.stdout.write("Return is "+ str(data))
    
posta bill 30.07.2017 - 13:00
fonte

2 risposte

1

Per un volume elevato di richieste, la creazione di una nuova connessione per ogni richiesta non è probabilmente efficiente. Inoltre, l'avvio di un nuovo processo Python per ogni richiesta non è troppo veloce: sul mio sistema, l'avvio di CPython senza eseguire alcuna operazione richiede da 60 ms a 10 ms a seconda della versione di cache e Python. Al contrario, l'avvio di un processo in Bash, Perl o un programma nativo è di circa 10 × più veloce.

Se puoi fare meglio dipende interamente dall'interfaccia presunta dal tuo sistema. Per esempio. se il sistema è in grado di fornire più nomi di file contemporaneamente, è possibile:

connect_db()
prepare_statement()
for filename in sys.argv[1:]:
  data = execute_statement(filename)
  print_result(data)
close_db()

Ma nota che il numero di parametri della riga di comando e la dimensione totale dei parametri della riga di comando possono essere piuttosto limitati.

Idealmente, lo script leggerà i nomi dei file da STDIN, ad es. come un nome di file per riga. Ciò consentirebbe allo script di elaborare tutti i file all'interno di un singolo processo.

Se non è possibile modificare l'interfaccia utilizzata dal sistema (ovvero invocare un eseguibile arbitrario con il nome file come unico argomento della riga di comando), potrebbe essere più veloce eseguire lo script Python come server TCP su localhost. È quindi possibile scrivere un semplice programma wrapper che invia il nome file come richiesta TCP al server e stampa la risposta. Se il wrapper non è scritto in Python, l'intera richiesta potrebbe essere terminata prima che un interprete Python possa avviarsi completamente.

Pseudocodice del client:

socket = connect()
write(socket, sys.argv[1])
flush(socket)
response = read(socket)
print(response)

Pseudocodice server:

connect_db()
prepare_statement()

server = listen()

while True:
  client = accept(server)
  filename = read(client)

  data = execute_statement(filename)

  write(client, data)
  close(client)

close(server)

close_db()

Poiché il client è un programma estremamente semplice, è possibile ottimizzare i tempi di avvio scrivendo il client in C.

Se hai veramente un milione di documenti che devono essere elaborati in batch contemporaneamente, anche piccole ottimizzazioni come non usare Python o elaborare più file per processo possono aggiungere fino a molte ore di salvataggio. Ma in generale: prima assicurati di avere un problema di prestazioni, quindi valuta la soluzione problematica, quindi prova qualcosa e confronta la soluzione tentata con l'implementazione originale. L'ottimizzazione è facile da sbagliare senza dati rigidi.

    
risposta data 30.07.2017 - 18:29
fonte
3

È possibile scrivere un programma daemon che rimane in esecuzione in background e il programma daemon mantiene aperta la connessione al database. Il programma principale si collegherà quindi al programma daemon, preferibilmente senza SSL, in modo che la connessione sia il più leggera possibile. Se il daemon è in esecuzione sulla stessa macchina, la crittografia sarebbe inutile.

Avrai bisogno dell'interfaccia più leggera possibile tra il programma principale e il demone.

Potresti avere una specie di meccanismo di spegnimento del timeout nel daemon. Per esempio. se nessuna richiesta è stata elaborata negli ultimi 10 secondi, spegni il demone.

Ovviamente, avrai bisogno di un qualche tipo di meccanismo per avviare automaticamente il demone, se non è in esecuzione.

Prima di farlo, tuttavia, assicurati che la connessione al database sia il collo di bottiglia. Non ottimizzarlo prematuramente!

    
risposta data 30.07.2017 - 18:22
fonte

Leggi altre domande sui tag