2012-10-17 10 views
8

Ho un grande tavolo con 10 m di file. E ho bisogno di ottenere un valore statistico per ogni riga. Ho una funzione che genera questo valore, ad esempio GetStatistic(uuid). Questa funzione funziona molto lento e il valore risultato non cambia spesso, quindi ho creato colonna Statistic nel mio tavolo, e una volta al giorno eseguire query come questa:Postgresql. Può eseguire la query di aggiornamento in paralell?

UPDATE MyTable SET Statistic = GetStatistic(ID); 

E nella query di selezione che uso colonna Statistic senza chiamare GetStatistic funzioni.

Il problema è che il mio server di produzione ha 64 CPU e molta memoria, quindi quasi tutti i DB possono essere memorizzati nella RAM, ma questa query utilizza solo una CPU e richiede 2 o 3 ore per essere eseguita.

GetStatistic utilizza le tabelle, che sono costanti durante tutta l'esecuzione della query UPDATE. Posso modificare la query per ottenere Postgre per calcolare GetStatistic in parallelo per diverse righe contemporaneamente, utilizzando tutte le CPU disponibili?

+0

Perché utilizzare una funzione, c'è qualcosa che non può essere realizzato da SQL semplice? La funzione richiede solo i valori della riga corrente o coinvolge anche altre fonti di dati (: = tabelle)? BTW: mostraci la funzione. – wildplasser

+0

Controlla il piano di questa query, vedrai che questa funzione è chiamata 10M volte. Forse sarebbe meglio scriverlo in puro SQL e potrebbe essere molto più veloce. –

risposta

9

PostgreSQL esegue ogni query in un singolo backend, che è un processo con un singolo thread. Non può utilizzare più di una CPU per una query. È anche un po 'limitato in quale concomitanza I/O è possibile ottenere all'interno di una singola query, in realtà solo facendo I/O simultaneo per scansioni di indice bitmap e altrimenti facendo affidamento sul sistema operativo e sul sistema disco per I/O simultanei.

Pg è buono a carichi simultanei di molte query più piccole ed è facile saturare il sistema in questo modo, non è altrettanto valido per sfruttare al meglio le risorse di sistema per una o due query veramente grandi.

Quello che puoi fare è dividere il lavoro in blocchi e distribuirli ai lavoratori. Hai accennato a questo con:

Posso modificare la query per ottenere Postgre per calcolare GetStatistic in parallela per i diversi file contemporaneamente, utilizzando tutte le CPU avaliable?

ci sono una varietà di strumenti, come DBlink, PL/Proxy, pgbouncer e PgPool-II che sono stati progettati per aiutare con questo tipo di lavoro. In alternativa, puoi farlo da solo, avviando 8 operatori che si collegano al database e eseguono le istruzioni UPDATE ... WHERE id BETWEEN ? AND ? con intervalli di ID non sovrapposti. Un'opzione più sofisticata è quella di avere un controller di coda che distribuisca intervalli di circa 1000 ID per i lavoratori che vanno da UPDATE a quell'intervallo chiedendone uno nuovo.

Si noti che 64 CPU non significa che 64 operatori concorrenti siano l'ideale. Anche l'I/O del disco è un fattore decisivo per quanto riguarda le scritture. È possibile semplificare un po 'l'I/O se si impostano le transazioni UPDATE per l'uso di commit_delay e (se sicuro per i requisiti aziendali per questi dati) synchronous_commit = 'off', quindi il carico da sincronizzare dovrebbe essere ridotto in modo significativo. Nondimeno, è probabile che il rendimento migliore sarà raggiunto ben al di sotto di 64 lavoratori concorrenti.

È molto probabile che la tua funzione GetStatistic possa essere resa molto più veloce convertendola in una funzione o vista inlineabile di SQL, piuttosto che ciò che è presumibilmente una funzione PL/pgSQL procedurale a ciclo continuo che è al momento. Potrebbe aiutare se hai mostrato questa funzione.

Problemi correlati