2016-05-04 19 views
6
OS=centos 6.7 [Dedicated server] 
memory=15G  
cpu=Intel(R) Xeon(R) CPU E5-2403 
mysql= V 5.1.73  

Ecco una tabella MyISAM e contiene circa 5 milioni di righe di dati. In ogni 5-6 minuti vengono inseriti dati per circa 3000 utenti (ad esempio, velocità di upload e download, stato della sessione ecc.).Ottimizzazione MySQL per grande tavolo myisam

informazioni

Tabella: descrivere "radacct"

enter image description here

my.cnf

enter image description here

enter image description here

Da log di MySQL query lente uno della query che richiede più tempo è inferiore a

Query_time: 7.941773 Lock_time: 0.155912 Rows_sent: 1 Rows_examined: 5377 
use freeradius; 
SET timestamp=1461582118; 
SELECT sum(acctinputoctets) as upload, 
     sum(acctoutputoctets) as  download 
    FROM radacct a 
    INNER JOIN (SELECT acctuniqueid, MIN(radacctid)  radacctid 
        FROM radacct 
        WHERE username='batman215' 
        and acctstarttime between '2016-02-03 12:10:47' 
              and '2016-04-25 16:46:01' 
        GROUP BY acctuniqueid) b 
     ON a.acctuniqueid = b.acctuniqueid 
     AND a.radacctid = b.radacctid; 

spiegare risultato di una query

enter image description here

quando ci sono molti utenti che tentano di vedere la loro larghezza di banda consumata il server non può soddisfare le richieste a causa di carico elevato e IO. C'è qualcosa che posso fare per ottimizzare ulteriormente il database?

indici di tabella "radacct"

enter image description here

spiegare query senza utilizzare \ G

enter image description here

Grazie

+1

Mostrate quali sono i vostri indici e potete gentilmente postare l'output di spiegare orizzontalmente (più facile da confrontare) – e4c5

+0

mostrare anche il vostro indice. –

+0

Si potrebbe provare ad aggiungere un indice multi colonna sul nome utente e sui campi acctstarttime. – Shadow

risposta

7

Lavoriamo questo partendo con la query interiore, che is:

 SELECT acctuniqueid, 
       MIN(radacctid) radacctid 
      FROM radacct 
     WHERE username='batman215' 
      and acctstarttime between '2016-02-03 12:10:47' 
           and '2016-04-25 16:46:01' 
     GROUP BY acctuniqueid 

Stai cercando una corrispondenza di uguaglianza su username e una corrispondenza di intervallo su acctstarttime. Quindi stai utilizzando acctuniqueid per raggruppare e estraendo un valore estremo (MIN()) da radacctid.

Pertanto, per accelerare questa sottoquery, è necessario il seguente indice composto.

(username, acctstarttime, acctuniqueid, radacctid) 

Come funziona? Pensa a un indice (questi sono gli indici BTREE) come elenco ordinato dei valori in esso contenuti.

  1. Il motore di query casuale accede alla lista - veloce, O (log (n)) - per trovare la prima voce corrispondente username e la fascia bassa del range BETWEEN.
  2. Quindi esegue la scansione in sequenza dell'elenco, voce per voce, fino a raggiungere la fascia alta dell'intervallo BETWEEN. Questa è chiamata scansione dell'indice .
  3. Mentre esegue la scansione, cerca ogni nuovo valore di acctuniqueid, in ordine e quindi prende il valore più basso - il primo in ordine - di radacctid, quindi salta al valore successivo di accuniqueid.Si chiama indice indice allentato ed è miracolosamente economico.

Quindi, aggiungere quell'indice composto. Questo probabilmente farà una grande differenza per le prestazioni della tua query.

La query esterna è simile a questa.

SELECT sum(acctinputoctets) as upload, 
     sum(acctoutputoctets) as  download 
    FROM radacct a 
INNER JOIN ( /*an aggregate 
       * yielding acctuniqueid and raddactid 
       * naturally ordered on those two columns 
       */ 
      ) b ON a.acctuniqueid = b.acctuniqueid 
       AND a.radacctid =  b.radacctid 

per questo è necessario il composto di copertura dell'indice

(acctuniqueid, radacctid, acctinputoctets, acctoutputoctets) 

Questa parte della query è soddisfatto con la magia indice.

  1. Le prime due colonne dell'indice consentono la ricerca di ciascuna riga necessaria, in base al risultato della query interna.
  2. Il motore di query può quindi eseguire la scansione dell'indice sommando i valori delle altre due colonne.

(questo è chiamato un copre indice perché contiene alcune colonne che sono presenti solo perché vogliamo che i loro valori, non perché vogliamo loro indicizzati. Alcuni altri marche e modelli di DBMS permettono colonne aggiuntive da inserire negli indici senza renderli ricercabili.Questo è un po 'più economico, specialmente sulle operazioni INSERT. MySQL non lo fa.)

Quindi, il tuo primo elemento di azione: aggiungi questi due indici composti e riprova la query.

Sembra, dalla tua domanda, che hai inserito molti indici a colonna singola sul tuo tavolo nella speranza che accelerino le cose. Questo è un famigerato antipattern nella progettazione di database. Con rispetto, dovresti sbarazzarti di tutti gli indici che non conosci di cui hai bisogno. Non aiutano le query e rallentano INSERTS. Questo è il tuo secondo oggetto d'azione.

In terzo luogo, leggi questo http://use-the-index-luke.com/ È molto utile.

Suggerimento per professionisti: hai visto come ho formattato la query? Sviluppare una convenzione di formattazione personale che mostri chiaramente tabelle, colonne, condizioni ON e altri aspetti di una query è estremamente importante quando devi comprenderne una.

+0

Il server viene fornito più che adeguatamente per questa applicazione. Questo è un caso di algoritmi (indici) che fanno una differenza maggiore rispetto alla potenza di fuoco bruta. –

+0

Gli indici a colonna singola sono lì in modo che query come 'select username, framedipaddress, servicetype FROM radacct WHERE username = 'batman215'' può farne uso, correggimi se no. Grazie, apprezzo il tempo che hai dedicato e le preziose intuizioni. –

+1

Un indice composto che inizia con 'username' accelererà anche la query che hai menzionato sopra. –

0
   WHERE username='batman215' 
       and acctstarttime between ... 

elemosina per INDEX(username, acctstarttime) in questo ordine.

ON a.acctuniqueid = b.acctuniqueid 
    AND a.radacctid = b.radacctid; 

implora per INDEX(acctuniqueid, radacctid) (in qualsiasi ordine) (o di un indice di copertura del Ollie).

"In ogni 5-6 minuti vengono inseriti dati per circa 3000 utenti" chiede InnoDB invece di MyISAM. MyISAM esegue blocchi di tabelle, pertanto l'inserimento di "inserimento" interferisce con altre query. Conversion tips.