Consigli su come ridimensionare e migliorare i tempi di esecuzione di una query basata su pivot & # 8221; su un miliardo di righe, aumentando un milione al giorno

StackOverflow https://stackoverflow.com/questions/1002086

Domanda

La nostra azienda sta sviluppando un progetto interno per analizzare i file di testo. Quei file di testo sono composti da metadati che vengono estratti usando espressioni regolari. Dieci computer analizzano i file di testo 24 ore su 24, 7 giorni su 7 e alimentano un database Intel Xeon SQL Server 2005 di fascia alta con i metadati estratti.

Lo schema del database semplificato è simile al seguente:

Items

| Id | Name   |
|----|--------|
| 1  | Sample |
Items_Attributes

| ItemId | AttributeId |
|--------|-------------|
| 1      | 1           |
| 1      | 2           |
Attributes

| Id | AttributeTypeId | Value |
|----|-----------------|-------|
| 1  | 1               | 500mB |
| 2  | 2               | 1.0.0 |
AttributeTypes

| Id | Name    |
|----|---------|
| 1  | Size    |
| 2  | Version |

Esistono molti tipi di file di testo distinti con metadati distinti all'interno. Per ogni file di testo abbiamo un Item e per ogni valore di metadati estratto abbiamo un Attribute.

Items_Attributes ci consente di evitare i valori duplicati di Attribute che evitano che le dimensioni del database aumentino di x ^ 10.

Questo particolare schema ci consente di aggiungere dinamicamente nuove espressioni regolari e di ottenere nuovi metadati da nuovi file elaborati indipendentemente dalla struttura interna che hanno.

Inoltre, ciò ci consente di filtrare i dati e di ottenere report dinamici in base ai criteri dell'utente. Stiamo filtrando per Attributo e quindi ruotando il gruppo di risultati ( http://msdn.microsoft.com/en-us/library/ms177410.aspx ). Quindi questa query pseudo-sql di esempio

SELECT FROM Items WHERE Size = @A AND Version = @B

restituisce una tabella pivotata come questa

| ItemName | Size  | Version |
|----------|-------|---------|
| Sample   | 500mB | 1.0.0   |

L'applicazione è in esecuzione da mesi e le prestazioni sono diminuite terribilmente al momento non è più utilizzabile. I rapporti non dovrebbero richiedere più di 2 secondi e la tabella Items_Attributes aumenta in media di 10.000.000 di righe alla settimana. Tutto è correttamente indicizzato e abbiamo impiegato molto tempo per analizzare e ottimizzare i piani di esecuzione delle query.

Quindi la mia domanda è: come lo ridimensioneresti per ridurre i tempi di esecuzione dei rapporti?

Siamo arrivati ??con queste possibili soluzioni:

  • Acquista altro hardware e imposta un cluster di SQL Server. (abbiamo bisogno di consigli sulla corretta strategia di "raggruppamento")
  • Utilizza un database chiave / valore come HBase (non sappiamo davvero se risolverebbe il nostro problema)
  • Utilizza un ODBMS anziché un RDBMS (abbiamo preso in considerazione db4o)
  • Sposta il nostro software sul cloud (non abbiamo esperienza)
  • Genera staticamente report in fase di esecuzione. (non vogliamo davvero)
  • Visualizzazioni indicizzate statiche per report comuni (il rendimento è quasi lo stesso)
  • De-normalizzare lo schema (alcuni dei nostri report coinvolgono fino a 50 tabelle in una singola query)
È stato utile?

Soluzione

Forse questo white paper del team CAT di SQL Server sulle insidie ??del modello di database Entity-Attribute-Value può aiutare: http://sqlcat.com/whitepapers/archive/2008/09/03/best-practices- per-semantica-data-modeling-per-performance-and-scalability.aspx

Altri suggerimenti

Comincerei dalla pubblicazione di metadati di tabelle esatte (insieme a dettagli di indicizzazione), testo di query esatto e piano di esecuzione.

Con il tuo attuale layout di tabella, la query è simile a questa:

SELECT FROM Items WHERE Size = @A AND Version = @B

non può trarre vantaggio dall'uso di un indice composito su (Dimensione, Versione) , poiché è impossibile costruire un tale indice.

Non puoi nemmeno creare una vista indicizzata, poiché conterrebbe un self-join su attributi .

Probabilmente la decisione migliore sarebbe quella di denormalizzare la tabella in questo modo:

id  name  size  version

e crea un indice su (dimensione, versione)

Ha lavorato con tali schemi molto tempo. Non si comportano mai bene. La cosa migliore è semplicemente archiviare i dati di cui hai bisogno, nel formato:

| ItemName | Dimensione | Versione | | ---------- | ------- | --------- | | Campione | 500mB | 1.0.0 |

Quindi non è necessario ruotare. E a proposito, per favore non chiamare il tuo schema EAV originale " normalizzato " - non è normalizzato.

Mi sembra di inviare alcune query OLAP su un database ottimizzato per le transazioni OLTP. Non conoscendo i dettagli, consiglierei di creare un "datawarehouse" separato ottimizzato per il tipo di query che stai facendo. Ciò implicherebbe l'aggregazione di dati (se possibile), la denormalizzazione e anche la presenza di una base di dati, che ha circa 1 giorno di età. Aggiorneresti i dati in modo incrementale ogni giorno o ad ogni intervallo desiderato.

Si prega di pubblicare DDL e indici esatti, se si hanno indici nelle colonne ID, la query genererà una scansione

invece di qualcosa del genere

SELECT FROM Items WHERE Size = @A AND Version = @B

devi farlo

SELECT FROM Items WHERE ID = 1

in altre parole devi prendere i valori del testo, trovare gli ID su cui stai indicizzando e quindi usarli come query per restituire risultati

Probabilmente è anche una buona idea guardare la funzione di partizionamento per distribuire i tuoi dati

il clustering viene eseguito per disponibilità non per prestazioni, se un nodo muore (il cluster attivo), l'altro nodo (il cluster passivo) diventerà attivo .... ovviamente c'è anche un cluster attivo attivo ma questa è un'altra storia

Una soluzione a breve termine potrebbe essere l'uso di partizionamento orizzontale . Suppongo che la tua tabella più grande sia Items_Attributes . È possibile partizionare orizzontalmente questa tabella, inserendo ciascuna partizione in un filegroup separato su un controller del disco separato.

Questo presuppone che tu non stia provando a riferire contemporaneamente su tutti gli ItemId .

Citi 50 tabelle in una singola query. Mentre SQL Server supporta fino a 256 tabelle in una singola query monolitica, adottare questo approccio riduce le possibilità che l'ottimizzatore produca un piano efficiente.

Se sei unito allo schema così com'è, considera di suddividere le tue query di report in una serie di passaggi che materializzano i loro risultati in tabelle temporanee (#). Questo approccio consente di eseguire le parti più selettive della query in modo isolato e, nella mia esperienza, può offrire grandi vantaggi in termini di prestazioni. Le query sono generalmente anche più gestibili.

Inoltre (un po 'a lungo, questo) non dici quale versione del server SQL stai utilizzando; ma se sei su SQL 2005, dato il numero di tabelle coinvolte nei tuoi rapporti e il volume di dati, vale la pena verificare che il tuo server SQL sia patchato almeno su SP2.

Ho lavorato su un progetto ETL utilizzando tabelle con un numero di righe in centinaia di milioni, in cui abbiamo scoperto che l'ottimizzatore di query in SQL 2005 RTM / SP1 non è stato in grado di produrre coerentemente piani efficienti per query che si uniscono a più di 5 tabelle in cui uno o più di i tavoli erano di questa scala. Questo problema è stato risolto in SP2.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top