2010-10-17 16 views
9

Ho un'app che ha bisogno di aggiornare una grande quantità di dati su un gran numero di voci. Fondamentalmente fa circa 7000 inserti e/o aggiornamenti, ma richiede un tempo molto lungo (come quasi 9 minuti ... in media di circa 0,08 secondi per query). In sostanza, sto cercando accelerazioni generali per fare più richieste di questo tipo (non mi aspetto una risposta specifica al mio vago esempio ... è solo per, si spera, una spiegazione).Accelerare un gran numero di aggiornamenti e inserimenti mysql

Ecco alcuni esempi di profilazione delle richieste:

SELECT `habitable_planets`.* FROM `habitable_planets` WHERE (timestamp = '2010-10-15T07:30:00-07:00') AND (planet_id = '2010_Gl_581_c') 

INSERT INTO `habitable_planets` (`planet_id`, `timestamp`, `weather_air_temp`, `weather_cell_temp`, `weather_irradiance`, `weather_wind_float`, `biolumin_to_date`, `biolumin_detected`, `craft_energy_usage`, `craft_energy_consumed_to_date`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 

SELECT `habitable_planets`.* FROM `habitable_planets` WHERE (timestamp = '2010-10-15T07:45:00-07:00') AND (planet_id = '2010_Gl_581_c') 

INSERT INTO `habitable_planets` (`planet_id`, `timestamp`, `weather_air_temp`, `weather_cell_temp`, `weather_irradiance`, `weather_wind_float`, `biolumin_to_date`, `biolumin_detected`, `craft_energy_usage`, `craft_energy_consumed_to_date`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 

Ripetere fino alla nausea (beh, circa 7.000 volte). Questo è un aggiornamento che raccoglie i dati generati a intervalli su un periodo di 24 ore e quindi effettua un massiccio aggiornamento al database una volta al giorno. Visto il limitato bit che ho mostrato, ci sono suggerimenti per accelerare questo processo?

Ad esempio ... avrebbe senso, piuttosto che eseguire una selezione per ciascun timestamp, eseguire una selezione per un intervallo tutto in una volta e quindi scorrere su di essi nello script?

vagamente come:

SELECT `habitable_planets`.* FROM `habitable_planets` WHERE (planet_id = '2010_Gl_581_c') 

assegnare che risultano $foo e poi fare:

foreach ($foo as $bar) 
{ 
    if ($bar['timestamp'] == $baz) // where $baz is the needed timestamp 
    { 
    // do the insert here 
    } 
} 

EDIT: Per aggiungere un po 'per questo, una cosa che ha migliorato la reattività nella mia situazione era per modificare un gruppo di codice che ha verificato la presenza di un record e ha fatto un inserimento o un aggiornamento in base al risultato utilizzando una query sql INSERT... ON DUPLICATE KEY UPDATE. Ciò ha comportato un aumento della velocità di circa il 30% nel mio caso particolare, in quanto ha eliminato almeno un viaggio nel database dall'equazione e oltre migliaia di richieste che questo aggiunge.

risposta

16

Alcuni link utili:

Da MySQL Documentazione:

Speed of INSERT Statements dice:

  • Se si sta inserendo molte righe dallo stesso cliente allo stesso tempo, l'uso istruzioni INSERT con più valori liste per inserire più righe alla volta . Questo è considerevolmente più veloce (molte volte più veloce in alcuni casi) rispetto a utilizzando istruzioni INSERT separate a riga singola. Se si aggiungono dati a una tabella non vuota, è possibile ottimizzare la variabile bulk_insert_buffer_size su rendendo l'inserimento dei dati ancora più veloce.

  • Se più client inseriscono molte righe, è possibile ottenere una maggiore velocità utilizzando l'istruzione INSERT DELAYED.

  • Per una tabella MyISAM, è possibile utilizzare inserti simultanei per aggiungere righe alla stesso tempo che selezionano le dichiarazioni sono in esecuzione, se non ci sono righe eliminate nel bel mezzo del file di dati.

  • Quando si carica una tabella da un file di testo, utilizzare LOAD DATA INFILE. Questo è in genere 20 volte più veloce rispetto all'utilizzo delle istruzioni INSERT .

  • Con un po 'di lavoro aggiuntivo, è possibile eseguire CARICHI DATI INFILATI eseguire anche più veloce per una tabella MyISAM quando la tabella ha molti indici.

+1

+1. Buona risposta esauriente. – sberry

2

Se non siete già, utilizzare le istruzioni preparate (sia tramite mysqli, PDO, o qualche altra libreria DB che li supporta). Riutilizzare la stessa dichiarazione preparata e semplicemente modificare i valori dei parametri aiuterà ad accelerare le cose, dal momento che il server MySQL deve solo analizzare la query una volta.

INSERT s può essere in batch fornendo più serie di VALUES - una singola query che inserisce molte righe è molto più veloce di un numero equivalente di singole query ciascuna inserendo una riga.

2

Quello che suggerisci è corretto. Prova a ridurre la quantità di query che invii al server poiché questo ti farà risparmiare dal sovraccarico di comunicazione.

Ovviamente, se la query di selezione a distanza iniziale restituisce troppi dati, è possibile che si verifichi un collo di bottiglia su PHP.

1

Probabilmente userei una procedura memorizzata se possibile e basta chiamarla dal mio codice applicazione. Inoltre, penserei all'indicizzazione corretta e possibilmente aggiungendo una chiave sostitutiva sostitutiva basata integer per planet_id come una chiave di 13 byte non sarà performante in join e ricerche come un intero di 4 byte.

(ho appena letto che ci sono stimati a 10 milioni di trilioni di pianeti abitabili nell'universo così forse è meglio utilizzare bigint unsigned: P)

drop procedure if exists update_insert_habitable_planets; 

delimiter # 

create procedure update_insert_habitable_planets 
(
in p_planet_id int unsigned, 
in p_timestamp datetime, 
) 
proc_main:begin 

    start transaction; 

    -- bulk update/insert whatever 

    commit; 

end proc_main # 

delimiter ; 
+0

* "10 milioni trilioni" * - 10 quintilioni :) – BadHorsie

Problemi correlati