2010-03-13 9 views
9

Nella nostra applicazione, raccogliamo dati sulle prestazioni del motore automobilistico, fondamentalmente dati di origine sulle prestazioni del motore in base al tipo di motore, al veicolo che lo percorre e al design del motore. Attualmente, la base per i nuovi inserti di riga è un periodo di on-off del motore; monitoriamo le variabili di prestazione in base a una modifica dello stato del motore da attivo a inattivo e viceversa. Il relativo engineState tabella seguente aspetto:In MySQL, qual è il progetto di query più efficace per unire tabelle di grandi dimensioni con molte o molte relazioni tra i predicati di join?

+---------+-----------+---------------+---------------------+---------------------+-----------------+ 
| vehicle | engine | engine_state | state_start_time | state_end_time  | engine_variable | 
+---------+-----------+---------------+---------------------+---------------------+-----------------+ 
| 080025 | E01  | active  | 2008-01-24 16:19:15 | 2008-01-24 16:24:45 |    720 | 
| 080028 | E02  | inactive  | 2008-01-24 16:19:25 | 2008-01-24 16:22:17 |    304 | 
+---------+-----------+---------------+---------------------+---------------------+-----------------+ 

Per un'analisi specifica, vorremmo analizzare il contenuto tabella basata su una granularità fila di minuti, piuttosto che l'attuale base di stato motore attivo/inattivo. Per questo, stiamo pensando di creare una semplice tabella productionMinute con una riga per ogni minuto nel periodo che stiamo analizzando e unendo le tabelle productionMinute e engineEvent alle colonne di data e ora in ogni tabella. Quindi, se il nostro periodo di analisi è dal 2009-12-01 al 2010-02-28, creiamo una nuova tabella con 129.600 righe, una per ogni minuto di ogni giorno per quel periodo di tre mesi. Le prime righe della tabella productionMinute:

+---------------------+ 
| production_minute | 
+---------------------+ 
| 2009-12-01 00:00 | 
| 2009-12-01 00:01 | 
| 2009-12-01 00:02 |  
| 2009-12-01 00:03 | 
+---------------------+ 

Il join tra le tabelle sarebbero:

 FROM engineState AS es 
LEFT JOIN productionMinute AS pm ON pm.production_minute >= es.state_start_time 
           AND pm.production_minute <= es.event_end_time 

Questa join, tuttavia, porta in primo piano molteplici tematiche ambientali:

  1. Il engineState tabella ha 5 milioni di righe e la tabella productionMinute ha 130.000 righe
  2. Quando unLa rigasi estende per più di un minuto (ad es. la differenza tra es.state_start_time e es.state_end_time è maggiore di un minuto), come avviene nell'esempio precedente, non vi sono più righe productionMinute tabella che si uniscono ad una singola riga engineState tabella
  3. Quando v'è più di un motore in funzione durante qualsiasi data minuto, anche secondo l'esempio precedente, più engineState righe della tabella si uniscono ad un singolo productionMinute fila

In testare nostra logica ed utilizzando solo un piccolo estratto tavolo (un giorno anziché 3 mesi, per la tabella productionMinute) la query impiega più di un'ora per generare. Nella ricerca di questo articolo al fine di migliorare le prestazioni in modo che fosse possibile interrogare tre mesi di dati, i nostri pensieri erano di creare una tabella temporanea dallo engineEvent, eliminando tutti i dati della tabella che non sono critici per l'analisi e unendo il tabella temporanea alla tabella productionMinute. Stiamo anche pianificando di sperimentare diversi join, in particolare un join interno, per vedere se ciò migliorerebbe le prestazioni.

Qual è il miglior design di query per l'unione di tabelle con le molte: molte relazioni tra i predicati di join come descritto sopra? Qual è il miglior tipo di join (sinistra/destra, interno)?

+0

Un esempio concreto di quale tipo di rapporto si sta tentando di generare sarebbe di aiuto. È possibile che non sia necessario espandere le osservazioni al minuto e creare direttamente i risultati. Inoltre, quali indici hai sulla tua tabella engineState? – Martin

+0

I tuoi reclami numero 2 e 3 non sono problemi ambientali, sono problemi di progettazione. Quello che voglio dire è che non riesco a vedere niente di sbagliato in nessuno dei due: sono veri perché hai disposto i tuoi dati in quel modo. Devi descrivere il motivo per cui lo vedi come un problema e chiarisci cosa ti aspetti dal join che hai scritto (quale significato semantico vorresti assegnargli: D). – Unreason

risposta

0

Le prestazioni dipenderanno da come sono strutturati i dati nelle tabelle.

un join esterno sinistro o destro è utile solo se si desidera tutti i valori nella tabella sinistra o destra per la proiezione selezionata e tali valori potrebbero non avere qualcosa nella tabella associata.

Affidati al tuo ottimizzatore di query per trovare l'algoritmo di join più efficiente per i tuoi dati ... è stato creato per sapere come fare bene il suo lavoro.Se hai problemi di prestazioni, guarda come sono strutturati e archiviati i dati.

+0

Grazie Jeremy; ma questa è esattamente la domanda che mi pongo: come dovremmo (ri) strutturare e archiviare i dati nelle tabelle per ottimizzare le prestazioni delle query quando si lavora su molte: molte relazioni tra i predicati di join e il funzionamento con set di dati di grandi dimensioni? Tieni presente che non siamo legati al nostro design attuale perché possiamo utilizzare tabelle temporanee per ristrutturare i dati e inserire indici nei predicati di join ... ma questo è un approccio che ha funzionato per gli altri che affrontano una sfida di prestazioni simile? In caso contrario, quali sono gli approcci che hanno funzionato? – lighthouse65

+0

Ma questa non è la domanda che hai chiesto. Hai chiesto specificamente dei join. Se si dispone di un set di dati molto grande e si dispone di più campi che si desidera indicizzare, è preferibile utilizzare gli alberi B + per indicizzare i campi. Richiederà meno IO in quasi tutti i casi quando si esegue una query. Non sono sicuro di quanto controllo MySQL ti dia rispetto alle tecniche di indicizzazione che puoi utilizzare, ma se hai scelta, scegline una. Se non hai scelta, sospetto che usi B + Trees per indicizzare già e che specifichi un campo da indicizzare per coprirti. – joejoeson

+0

Grazie per il repost Jeremy. Credo che MySQL ci consenta di specificare il tipo di indice da utilizzare. Guarderemo più avanti questa opzione e pubblicherò ciò che troveremo. – lighthouse65

1

prestazioni di reperimento dei dati è la funzione di

  • velocità di accesso ai dati sul disco (dipende sulla esistenza di indici, le dimensioni della tabelle, dimensione della cache, I raw/velocità O)
  • numero di record che hanno bisogno di essere restituito (alcuni si unisce ridurre il numero di righe restituite , alcuni aumento, alcune condizioni possono essere applicati su indici alcuni devono andare i record)
  • numero di colonne che dovete restituire

Per tutti questi è possibile ottimizzare

  • aggiungendo indici
  • riducendo la dimensione della tabella suddividendo verticalmente (dividere la tabella in due o più tabelle semanticamente diverse - ad esempio se dalla tabella 5m lavori effettivamente solo con record 100k 99,5% delle volte potresti dividere la tabella in attivo/inattivo o simile)
  • se non puoi dividere verticalmente puoi dividere una tabella in orizzontale - numero di colonne che la tabella influenza anche la velocità di recupero (ma non tanto)
  • finalmente migliorare la velocità di I/O raw può essere ottenuta dividendo la tabella in modo trasparente su più hard disk (ma sai le proprietà del file system sottostante)

Gli indici hanno il maggiore impatto sulle prestazioni perché possono ridurre il tempo di accesso al disco e la velocità nelle operazioni di memoria di ordini di grandezza (girano O (n) per registrare O (n) al costo della manutenzione della struttura dell'indice; quindi rallentano gli aggiornamenti)

Per gli indici di velocità massima di recupero devono coprire tutto il join e dove le condizioni e le query devono essere scritte in modo che Query Optimizer possa determinare quale di questi offrirà il massimo vantaggio se eseguito per primo (massimo selettività).

Per esempio particolare cercare di benchmark differente combinazione di indici

  1. pm.production_minute deve essere indicizzato per assicurarsi
  2. con es.state_start_time e es.state_end_time si hanno 4 possibili opzioni su indici (che si può combinare):
    indice es.state_start_time indice
    su es.state_end_time indice
    su (es.state_start_time, es.state_end_time)
    indice (es.state_end_time , es.state_start_time)

Conoscere i dati consente di determinare quale è ottimale. Non sarei sorpreso se si scoprisse che avere gli ultimi due indici a due colonne avrebbe funzionato al meglio. Oppure con una singola colonna e un altro indice di due colonne (ma in ordine inverso di colonne).

In entrambi i casi, l'ottimizzatore discreto sarebbe in grado di determinare il set di risultati semplicemente leggendo gli indici e nemmeno guardando i record effettivi e riducendo notevolmente l'accesso al disco.

0

La mia esperienza è che MySQL Query Optimizer è piuttosto male. Quello in PostgreSQL è molto meglio.

Il tuo problema è che i tuoi dati sono strutturati per facilità di registrazione, non per facilità di analisi. Il mio suggerimento è di andare avanti e creare il tavolo temporaneo, ma non nel modo in cui si potrebbe immaginare. Penso che la cosa migliore da fare sia avere un passaggio post-elaborazione alla fine di ogni giornata che raccolga tutti i dati del giorno e crei voci minuto per minuto in una nuova tabella (idealmente su un altro mandrino) con un indice production_minute. Questo nuovo database sarà più veloce per eseguire le tue query analitiche e le query non rallenteranno sensibilmente la raccolta dei dati.

1

Sono d'accordo con vy32. È necessario eseguire questa query una volta e una sola volta per ottenere i dati in un formato adatto all'analisi. È necessario utilizzare uno strumento ETL appropriato (o heck, solo perl o qualcosa di semplice) per estrarre i dati dalla tabella engineState, calcolare il minuto di produzione, quindi caricarlo in un altro DB opportunamente modellato per le query del tipo di analisi.

Se pensi che il tuo problema attraverso di te sia solo denormalizzare i tuoi dati e assegnare numeri minuti come chiavi surrogate. Questo è un problema ETL relativamente facile (e comune) che non è performante in SQL diretto ma è semplice con altri linguaggi e strumenti.

Il tuo volume di produzione sarà facilmente gestito da un vero processo ETL.

0

Se ho capito correttamente, stai esaminando un problema di BI. Un layout di BI dovrebbe avere i dati operativi a parte quello consolidato.

Perché ciò accada (veloce e sporco) avrete bisogno di tre elementi.

  • I suoi dati operativi
  • un lavoro ETL, che ha bisogno solo fine di eseguire la query che avete mostrato e inserire il gruppo di risultati in un'altra tabella denormalizzato
  • tabelle denormalizzati dove potrete salvare i dati consilidated.

In questo modo si velocizzerà la query poiché ora sarebbe una selezione semplice.

Come in qualsiasi soluzione di BI, è necessario eseguire l'ETL su base giornaliera (a seconda delle esigenze di business) per aggiornare le informazioni denormalizzate.

D'altra parte, è possibile disattivare il modo BI e lavorare sullo schema/query corrente. Potresti aggiungere indici, statistiche, modificare tabelle ma a mio avviso questa non è una soluzione scalabile. Potresti risolvere il problema delle prestazioni per un database di tre mesi, ma cosa succede se hai un database di tre anni?

0

L'uso di un SINISTRO SINISTRA, UNIFORME INTERNO o GIUSTO JOIN è una differenza semantica - l'utilizzo di un diverso join per la prestazione non è solo una cattiva idea, significa che il rapporto tra tabelle non è stato completamente compreso i diversi tipi di JOIN possono restituire informazioni diverse perché significano cose diverse.

In genere, gli INNER JOIN sono molto ottimizzatori, poiché questo consente a diversi criteri di filtro dalla tua clausola WHERE e JOIN di essere spinti molto di più per migliorare le scansioni degli indici o le scansioni delle tabelle. I vincoli di integrità referenziale possono anche fornire le informazioni di ottimizzazione sui dati garantiti che esistono su entrambi i lati.

È necessario rivedere i piani di esecuzione e osservare le strategie di indicizzazione. Idealmente, si vogliono indici stretti e coprenti e si desidera vedere i repertori degli indici, le scansioni degli indici, le scansioni delle tabelle (in ordine di preferenza) nei piani.

In genere, si desidera che il modello venga normalizzato per l'elaborazione delle transazioni e denormalizzato per la creazione di report, ma due modelli sono fastidiosi da affrontare all'inizio, quindi si inizia cercando di eseguire report e analisi sui dati normalizzati e questo può funzionare per un po 'con indici migliori e guardando i piani di esecuzione.

Quando il reporting diventa troppo scadente su una forma normale ben indicizzata, vorrei esaminare la trasformazione dei dati in un modello dimensionale (dare un'occhiata alla metodologia di Kimball) con schemi a stella che hanno schemi molto semplici per la creazione di report (in genere tutti INNER JOINs e una semplice stella) e può essere ottimizzato molto bene sui sistemi di database tradizionali.

Problemi correlati