2016-02-01 10 views
13

Quindi ho uno script python che attraversa circa 350.000 oggetti dati e, in base ad alcuni test, ha bisogno di aggiornare una riga che rappresenta ciascuno di quegli oggetti in un db MySQl. Sto anche usando pymysql dato che ho avuto il minimo problema con esso soprattutto quando si inviano query di selezione di grandi dimensioni (selezionare le istruzioni con la clausola where column IN (....) che può contenere più di 100.000 valori).PyMySQL aggiornamenti diversi in una query?

Poiché ogni aggiornamento per ogni riga può essere diverso, ogni istruzione di aggiornamento è diversa. Ad esempio, per una riga potremmo voler aggiornare first_name ma per un'altra riga vogliamo lasciare intatto lo first_name e vogliamo aggiornare last_name.

Questo è il motivo per cui non voglio utilizzare il metodo cursor.executemany() che accetta una dichiarazione di aggiornamento generica e poi le trasmetti i valori come ho detto, ogni aggiornamento è diverso, quindi una dichiarazione di aggiornamento generica non è realmente lavoro per il mio caso. Inoltre, non voglio inviare oltre 350.000 dichiarazioni di aggiornamento singolarmente sul filo. Posso comunque raggruppare insieme tutte le mie dichiarazioni di aggiornamento e inviarle contemporaneamente?

Ho provato ad averli tutti in una query e utilizzando il metodo cursor.execute() ma non sembra che aggiorni tutte le righe.

+0

Quanti aggiornamenti di tipi diversi ci sono? vale a dire quante tabelle diverse stai aggiornando con quei terzi di un milione di valori? e quante colonne diverse su quei tavoli? Ad esempio, sono solo alcune dichiarazioni di aggiornamento diverse? –

+1

Esistono altre opzioni utili oltre alle query "una query" o "un terzo di milioni"? Che dire se i dati sono stati caricati in un 'work table' nel database e manipolati da quello? Database come giocare con i dati nelle tabelle? –

+0

@RyanVincent aggiornano tutti la stessa tabella ma la tabella ha 12 colonne e ogni istruzione di aggiornamento può aggiornare qualsiasi combinazione di colonne in una sola volta, da 1 a 10 colonne. –

risposta

4

SQL # 1: CREATE TABLE t con qualsiasi colonna che potrebbe essere necessario modificare. Effettuare tutti loro NULL (al contrario di NOT NULL).

SQL n. 2: eseguire un bulk INSERT (o LOAD DATA) di tutte le modifiche necessarie. Ad esempio, se si modifica solo first_name, immettere id e first_name, ma disporre delle altre colonne NULL.

SQL # 3-14:

UPDATE real_table 
    JOIN t ON t.id = real_table.id 
    SET real_table.first_name = t.first_name 
    WHERE t.first_name IS NOT NULL; 
# ditto for each other column. 

Tutti SQLs tranne 1 # sarà tempo. E, dal momento che lo UPDATE deve compilare un registro di annullamento, potrebbe scadere o comunque essere problematico. Vedi a discussion of chunking se necessario.

Se necessario, utilizzare funzioni come COALESCE(), GREATEST(), IFNULL(), ecc

Messa UPDATEs di solito implicano cattiva progettazione dello schema.

(Se Ryan salta con un 'risposta' invece di un 'commento', dovrebbe probabilmente ottenere la 'ricompensa'.)

+0

Ciao Rick, So che hai risposto alla mia altra domanda riguardante il connettore mysql, ma sto riscontrando un errore simile quando provo a caricare l'infile locale dati utilizzando la libreria pymysql. ottengo un errore di tubo rotto indipendentemente dal fatto che ho eseguito il codice dalla mia macchina o una macchina EC2 dove il DB è un RDS DB quindi dubito la rete è stata quella merda per una settimana di fila 'e_bytes rilancio err.OperationalError (2006, "Il server MySQL è andato via (% r)"% (e,)) pymysql.err.OperationalError: (2006, "Il server MySQL è andato via (BrokenPipeError (32, 'Broken pipe'))") ' –

5

Il tuo migliore prestazione sarà se è possibile codificare i "test" in la stessa logica SQL, in modo da poter far bollire tutto in una manciata di istruzioni UPDATE. O almeno ottenerne il maggior numero possibile, in modo che un numero inferiore di righe debba essere aggiornato individualmente.

Ad esempio:

UPDATE tablename set firstname = [some logic] 
WHERE [logic that identifies which rows need the firstname updated]; 

Non descrivere molto circa i test, quindi è difficile essere sicuri. Ma in genere puoi ottenere un sacco di logica nella tua clausola WHERE con un po 'di lavoro.

Un'altra opzione potrebbe essere quella di inserire la logica in una stored procedure. Continuerai a fare 350.000 aggiornamenti, ma almeno non stanno tutti "andando oltre il filo".Lo userei solo come ultima risorsa, però; la logica aziendale dovrebbe essere mantenuta nel livello dell'applicazione ogni volta che è possibile e le stored procedure rendono la tua applicazione meno portabile.