Come utilizzare il ritardo di inserimento con il motore InnoDB e utilizzare meno connessioni per le istruzioni di inserimento?


10

Sto lavorando a un'applicazione che coinvolge molte scritture di database, circa il 70% di inserti e il 30% di letture. Questo rapporto includerebbe anche gli aggiornamenti che considero una lettura e una scrittura. Tramite le istruzioni insert più client inseriscono i dati nel database tramite le istruzioni insert seguenti:

$mysqli->prepare("INSERT INTO `track` (user, uniq_name, ad_name, ad_delay_time ) values (?, ?, ?, ?)");

La domanda è: dovrei usare insert_delay o usare il meccanismo mysqli_multi_query perché l'istruzione insert utilizza ~ 100% cpu sul server. Sto usando il motore InnoDB sul mio database, quindi non è possibile inserire ritardi. L'inserimento sul server è ~ 36k / h e il 99,89% letto, inoltre sto usando l'istruzione select per recuperare i dati sette volte in una singola query , questa query impiega 150 secondi per l'esecuzione sul server. Che tipo di tecnica o meccanismo posso usare per questo compito? La memoria del mio server è di 2 GB, devo espandere la memoria ?. Dai un'occhiata a questo problema, qualsiasi suggerimento mi sarà grato.

Struttura del tavolo:

+-----------------+--------------+------+-----+-------------------+----------------+
| Field           | Type         | Null | Key | Default           | Extra          |
+-----------------+--------------+------+-----+-------------------+----------------+
| id              | int(11)      | NO   | PRI | NULL              | auto_increment |
| user            | varchar(100) | NO   |     | NULL              |                |
| uniq_name       | varchar(200) | NO   |     | NULL              |                |
| ad_name         | varchar(200) | NO   |     | NULL              |                |
| ad_delay_time   | int(11)      | NO   |     | NULL              |                |
| track_time      | timestamp    | NO   | MUL | CURRENT_TIMESTAMP |                |
+-----------------+--------------+------+-----+-------------------+----------------+

Il mio database presenta lo stato, mostra 41k inserimenti (scritture), che è molto lento per il mio database.

stato del database


Potete fornire la definizione della tabella? (tutte le colonne, i tipi di dati e gli indici)
ypercubeᵀᴹ

Puoi darci un breve frammento del tuo SHOW FULL PROCESSLISTquando sta prendendo il 100% di CPU? Quante connessioni stai permettendo vs quante sono state prese in questo periodo?
Derek Downey,

Si prega di eseguire questi due query: SHOW GLOBAL VARIABLES LIKE 'innodb%';ed SELECT VERSION();e mostrare la loro uscita.
RolandoMySQLDBA

Fornisci il numero di inserti al secondo che stai eseguendo.
dabest1,

Il tuo codice è molto sensibile all'iniezione SQL. Usa istruzioni preparate e valori parametrizzati.
Aaron Brown,

Risposte:


11

Dato che hai più scritture che letture, vorrei raccomandare quanto segue

La sintonia decente di InnoDB sarebbe la chiave

Pool di buffer (dimensionato da innodb_buffer_pool_size )

Poiché InnoDB non supporta INSERT DELAYED , l'utilizzo di un grande pool di buffer InnoDB è la cosa più vicina a INSERT DELAYED. Tutti i DML (INSERT, UPDATE e DELETE) verrebbero memorizzati nella cache del pool di buffer InnoDB. Le informazioni transazionali per le scritture vengono scritte immediatamente nei registri di ripetizione (ib_logfile0, ib_logfile1). Le scritture pubblicate nel pool di buffer vengono periodicamente scaricate dalla memoria sul disco tramite ibdata1 (InsertBuffer per indici secondari, doppio buffer di scrittura). Maggiore è il pool di buffer, maggiore è la quantità di INSERT che possono essere memorizzati nella cache. In un sistema con almeno 8 GB di RAM, utilizzare il 75-80% della RAM come innodb_buffer_pool_size. In un sistema con pochissima RAM, il 25% (per ospitare il sistema operativo).

CAVEAT: puoi impostare innodb_doublewrite su 0 per velocizzare ulteriormente le scritture, ma a rischio di integrità dei dati. Puoi anche velocizzare le cose impostando innodb_flush_method su O_DIRECT per impedire la memorizzazione nella cache di InnoDB sul sistema operativo.

Ripeti registri (dimensionato da innodb_log_file_size )

Per impostazione predefinita, i registri di ripetizione sono denominati ib_logfile0 e ib_logfile1 e sarebbero 5 MB ciascuno. La dimensione dovrebbe essere il 25% della dimensione innodb_buffer_pool_size. Se i registri di ripetizione esistono già, aggiungi la nuova impostazione in my.cnf, spegni mysql, cancellali e riavvia mysql .

Log Buffer (dimensionato da innodb_log_buffer_size )

Il buffer di registro conserva le modifiche nella RAM prima di scaricarle nei registri di ripetizione. L'impostazione predefinita è 8M. Maggiore è il buffer di registro, minore sarà l'I / O del disco. Fai attenzione con transazioni molto grandi, poiché ciò potrebbe rallentare COMMIT di millisecondi.

Accesso a più CPU

MySQL 5.5 e MySQL 5.1 InnoDB Plugin hanno impostazioni per consentire a InnoDB Storage Engine di accedere a più CPU. Ecco le opzioni che devi impostare:

  • innodb_thread_concurrency imposta il limite superiore sul numero di thread simultanei che InnoDB può tenere aperti. Di solito si consiglia di impostare per questo è (2 X Numero di CPU) + Numero di dischi. L'anno scorso ho appreso in prima persona dalla conferenza di Percona a New York che dovresti impostarlo su 0 per avvisare il motore di archiviazione InnoDB di trovare il miglior numero di thread per l'ambiente in cui è in esecuzione.
  • innodb_concurrency_tickets imposta il numero di thread che possono bypassare il controllo della concorrenza impunemente. Una volta raggiunto questo limite, il controllo della concorrenza dei thread diventa di nuovo la norma.
  • innodb_commit_concurrency imposta il numero di transazioni simultanee che possono essere impegnate. Poiché il valore predefinito è 0, la mancata impostazione consente a qualsiasi numero di transazioni di impegnarsi contemporaneamente.
  • innodb_thread_sleep_delay imposta il numero di millisecondi in cui un thread InnoDB può essere inattivo prima di rientrare nella coda InnoDB. L'impostazione predefinita è 10000 (10 sec).
  • innodb_read_io_threads ( impostalo su 3000) e innodb_write_io_threads ( impostalo su 7000) (entrambi da MySQL 5.1.38) assegnano il numero specificato di thread per letture e scritture. L'impostazione predefinita è 4 e il massimo è 64. Impostali su 64. Inoltre, imposta innodb_io_capacity su 10000.

Aggiorna a MySQL 5.5

Se hai MySQL 5.0, esegui l'upgrade a MySQL 5.5. Se hai MySQL 5.1.37 o precedenti, esegui l'upgrade a MySQL 5.5. Se si dispone di MySQL 5.1.38 o versioni successive e si desidera rimanere in MySQL 5.1, installare il plug-in InnoDB. In questo modo, puoi sfruttare tutte le CPU per InnoDB.


la memoria del mio server è di 2 GB, quindi in base alla memoria ho impostato il pool di buffer innodb su 500M e i file di log al 25% su pool, inoltre ho impostato il buffer di log su 64M. Ma il server è ancora molto occupato. Devo aggiornare la memoria? Anche il mio server è su Ubuntu a 32 bit, quindi al massimo posso impostare la memoria su 4 GB.
Shashank,

Se il server è solo per MySQL (nessun apache, nessun PHP), innodb_buffer_pool_size può arrivare al 75% di 2 GB, ovvero 1536 milioni. Se esegui l'upgrade a 4 GB, innodb_buffer_pool_size può essere 3G. I file di registro dovrebbero essere il 25% del pool di buffer come indicato.
RolandoMySQLDBA

Il server esegue apache2, mysql e php, dovrei cercare memoria di aggiornamento in questa situazione o esiste una soluzione ottimale se non il pool di buffer innodb?
Shashank,

Questo ragazzo non è d'accordo con te: percona.com/blog/2008/11/21/… Difficile discutere con Percona.
Zenexer,

Rolando: suggerisci di aggiungere alla risposta gli aggiornamenti per 5.6 e 5.7. I valori predefiniti sono cambiati; sono disponibili altre impostazioni; ecc. Forse includere Percona e MariaDB e punte 8.0.
Rick James,

2

INT (2) usa ancora 4 byte - forse intendevi TINYINT UNSIGNED?

Quanti valori diversi in setno? Se è piccolo, KEY (setno) non verrà mai utilizzato. INSERTing deve aggiornare tale indice; la rimozione del TASTO accelererà INSERIRE alcuni.

CHAR (10) - Sono flagsempre lunghi 10 caratteri? E in utf8? Forse potresti usare flag VARCHAR (10) CHARACTER SET ascii

Lancia i tuoi inserti: 100 alla volta verranno eseguiti 10 volte più velocemente. (Oltre 100 sta entrando in "rendimenti decrescenti".)

Qual è il valore di autocommit? Stai avvolgendo ciascun INSERT in INIZIA ... COMMIT? Qual è il valore di innodb_flush_log_at_trx_commit?


come ottengo l'inserimento in batch se i dati vengono inseriti tramite origine esterna come client diversi con valori diversi ... è affidabile se l'ho usato: codeinserisci in t_name (col1, col2, col3) valori (val1, val2, val3), (val1, val2, val3), (val1, val2, val3), (val1, val2, val3), (val1, val2, val3); code
Shashank,

1

Imposta una coda. L'applicazione scriveva in una riga 1 alla volta, quindi estraeva le righe e le inseriva in un database in batch in base al numero di righe della quantità di tempo trascorso dall'ultimo inserimento.

Ho visto dove raggruppare gli inserti 10.000 alla volta è il più veloce, quindi dovresti provare per trovare un punto debole.

È possibile creare il proprio sistema di code semplice o utilizzarne uno esistente. Ecco alcuni esempi: HornetQ e File :: Queue . Ecco un post su SE che elenca alcune altre buone opzioni: Code di messaggi in perl, php, python .


Sono d'accordo con questo approccio: sto raggruppando ~ 1500 inserti ogni 5 secondi su un'app ed è un secondo secondario. mysql sembra avere implementato internamente un meccanismo che rende gli inserimenti batch molto rapidi.
Don Wool,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.