Date post: | 03-Mar-2017 |
Category: |
Data & Analytics |
Upload: | marco-pozzan |
View: | 68 times |
Download: | 4 times |
#sqlsat589February 25th, 2017
Optimizing DAX
Marco Pozzan
#sqlsat589February 25th, 2017
Sponsor
#sqlsat589February 25th, 2017
Organizers
#sqlsat589February 25th, 2017
Chi sono
Community Lead 1nn0va (www.innovazionefvg.net)
Consulente Business Intelligence per (www.beantech.it)
Docente ITS all’Università di Pordenone
Partecipo agli eventi community
@marcopozzan.it
www.marcopozzan.it
http://www.scoop.it/u/marco-pozzan
http://paper.li/marcopozzan/1422524394
#sqlsat589February 25th, 2017
Agenda
La differenza tra FE ed SE
Tipi di query plan
Tool per ottimizzare DAX
Recap su Vertipaq
Ottimizzazioni di DAX
Conclusioni
#sqlsat589February 25th, 2017
In Vertipaq ci sono due motori completamente diversi comecaratteristiche, sono come due fratellini che assieme cercano dirisolvere la query DAX
Storage engine
Formula engine
Lo storage engine va sullo storage scandisce il contenuto delle tabelle erestituisce sempre tabelle come risultato
Le tabelle che restituisce lo storage engine sono utilizzate dal formulaengine per fare ulteriori calcoli
(SE) e (FE)
#sqlsat589February 25th, 2017
Storage engine (SE):
è incredibilmente veloce
è multi-thread quindi lavora su più core ed è in grado di parallelizzare moltissimo
non sa fare molte operazioni: select, matematica di bassissimo livello, applicaun filtro where e segue le relazioni per join
Formula engine (FE):
Tutte le altre operazioni vengono risolte da formula engine
Single-thread
Espressività
Considerazioni: bisogna codificare le query DAX in modo che si ottimizzil’uso di SE e si riduca il l’uso di FE perchè così si ha più velocità
(SE) e (FE)
#sqlsat589February 25th, 2017
Ogni task eseguito da SE va in cache e quindi produrranno un risultatoveloce la seconda volta che viene eseguito
Ogni compito eseguito da FE non va in cache e viene ripetuto di nuovo
Per creare delle buone ottimizzazioni analizziamo come vertipaq lavoracon e senza cache. Per svuotare la chace si utilizza il seguente script
Considerazioni: fare in modo che le parti delle nostre query utilizzino ilmeno possibile FE in quanto sono parti che vengono ogni voltaricalcolate
Cosa viene messo nella cache
#sqlsat589February 25th, 2017
Il «DAX Query Plan» indica ciò che Vertipaq farà. Ci sono due tipi diquery plan:
Logical query plan: praticamente inutile perchè descrive la definizionedell’algoritmo della query DAX e a patto che la query non sia molto complessanon contiene informazioni importanti
Fisical query plan: molto utile e ci dice quello che effettivamente ha fatto laquery.
Il query plan in tabular non è come sql che mostra frecce e colori ma èuna stringa di testo
Query plan
#sqlsat589February 25th, 2017
Query plan Optimization Flow
Build DAX Expression Tree
Build DAX Logical Plan
Simplify DAX Logical Plan
Build DAX Physical Plan
Execute DAX Physical Plan
Fire Logical Plan Event
Fire Physical Plan Event
#sqlsat589February 25th, 2017
Profiler SQL Server
DAX Studio (https://daxstudio.codeplex.com/)
Tool per le ottimizzazioni
#sqlsat589February 25th, 2017
Query End: E’ un evento che viene generato quando si cocnlude la query e riporta iltempo di esecuzione totale delle query e il tempo di lavoro della CPU
Dax Query Plan: è un evento che viene generato quando viene creato il query plan egenera la forma testuale del query plan
Vertipaq SE Query Cache Match: questo evento accade quando una query Vertipaqviene eseguita usando la cache
Vertipaq SE Query End: è l’evento che si genera quando viene eseguita una query dalloStorage Engine di Vertipaq per ritornare il risultato
Eventi che catturano i tool
#sqlsat589February 25th, 2017
Vediamo come viene risolta questa query
SQL Profiler
DAX Studio
Come lavorano?
#sqlsat589February 25th, 2017
DAX query plan (logical plan)
AddColumns : RelLogOp DependOnCols()() 0-0 Parametri Operatori
RequiredCols(0)(''[Result])
Sum_Vertipaq: ScaLogOp DependOnCols()() Tipo Operatore
Currency DominantValue=BLANK
Scan_Vertipaq: RelLogOp
DependOnCols()() 0-135
RequiredCols(126)('Internet
Sales Big'[Sales Amount])
'Internet Sales'[Sales Amount]: ScaLogOp DependOnCols(126)('Internet
Sales Big'[Sales Amount]) Currency
DominantValue=NONE
EVALUATErow ("Result",
SUM(
'Internet Sales Big'[Sales Amount]))Operatore
Operazioni
eseguite
Da Vertipaq
SQL Profiler DAX Studio
#sqlsat589February 25th, 2017
Column List (Elenco numero di colonna) (elenco nomi di colonna). RequiredCols (0, 1) ( 'Data'[CalendarYear], ‘Internet Sales Big' [SalesAmount]) o DependOnCols () ()
La ScaLogOp indica una dipendenza sul ramo sinistro DependOnCols(126) e ritorna uno scalare
sotto RelLogOp ci sono le Vertipaq query ritorna una tabella
«Crea una tabella con una colonna result che sarà riempita dalla SUM (SUM_Vertipaq) sulla colonna[Sales Amount] leggendo tutta la tabella (Scan_Vertipaq) Internet Sales Big»
DAX query plan (logical plan)
AddColumns : RelLogOp DependOnCols()() 0-0
RequiredCols(0)(''[Result])
Sum_Vertipaq: ScaLogOp DependOnCols()()
Currency DominantValue=BLANK
Scan_Vertipaq: RelLogOp
DependOnCols()() 0-135
RequiredCols(126)('Internet
Sales Big'[Sales Amount])
'Internet Sales'[Sales Amount]: ScaLogOp
DependOnCols(126)('Internet Sales Big'[Sales Amount]) Currency DominantValue=NONE
AddColumns
RelLog
Op
SubTreeScaLog
OpVertipaq Query
1
2
#sqlsat589February 25th, 2017
SinglestonTable è una tabella con una riga che rappresenta il comando ROW = [Result]
SpoolLookup i dati per result li cerca nella datacache che si chiama “ProjectFusion<Sum>“
ProjectionSpool nuova versione di AggrgationSpool contiene il risultato della VertipaqResultimportante l’etichetta #Records che sono il numero di righe in cache che sono usate
VertipaqResult risultato di una query xmlSQL. Ma non si sa quale query
#ValueCols n° di colonne numeriche e #FieldCols n° di colonne di altro tipo
DAX query plan (physical plan)
AddColumns: IterPhyOp LogOp=AddColumns IterCols(0)(''[Result])
SingletonTable: IterPhyOp LogOp=AddColumns IterCols(0)(''[Result])
SpoolLookup: LookupPhyOp LogOp=Sum_Vertipaq Currency
#Records=1 #KeyCols=258 #ValueCols=1
DominantValue=BLANK
ProjectionSpool<ProjectFusion<Sum>>: SpoolPhyOp #Records=1
VertipaqResult: IterPhyOp #FieldCols=0 #ValueCols=1
#sqlsat589February 25th, 2017
Vertipaq SE query
l’ FE genera una serie di operazioni che vengono inviate all’ SE
Quello che è eseguito da SE nel profiler è il «vertipaq SE query» (xmSQL).
Ci sono sempre 2 Vertipaq SE query.
vertipaq scan è quello che chiede FE all’ SE
vertipaq scan internal è quello che viene effettivamente eseguito da SE
SQL Profiler
DAX Studio
#sqlsat589February 25th, 2017
Query End
Query End ha una durata (Duration) e (CPUTime) in millisecondi
CPUTime = SE CPU =tempo eseguito per query (x tanti utenti devo ridurlo)
Duration = Total = tempo di attesa del risultato (diviso per n° core) (se hopochi utenti devo ridurlo e non me ne frega che la CPU sia 100%)
Se ho due thred in parallelo uno per core la Duration <= CPUTime
123 ms di SE (sommatoria dei Vertipaq Scan), 125-123 = 2 FE
Quando i due sono sotto i 10-15 millesecondi non ha senso ottimizzare
SQL Profiler DAX Studio
#sqlsat589February 25th, 2017
Compressione in Vertipaq
Vertipaq (simile compressione di pagina in SQL Server)
Identifica parti uguali nell’aria di memoria
Crea una struttura per rappresentare le parti uguali e ottiene la struttura compressa della colonna
Più efficiente di SQL perché si ragiona solo su una colonna con pochi valori distinti rispetto alla pagina di SQL in cui ho righe con più colonne e con meno valori distinti .
Vediamo come Vertipaq esegue la compressione
#sqlsat589February 25th, 2017
Run Length Encoding (RLE) - 1 livello
Potrei anche decidere di togliere la colonna inizio e tenere solo la fine
Children
1
1
1
1
1
...
2
2
2
2
2
2
2
2
....
Children Inizio Lunghezza
1 1 200
2 201 400
FirstName
Larry
Larry
Larry
...
Geoffrey
Geoffrey
Geoffrey
...
Alexa
Alexa
Alexa
...
Colleen
Colleen
...
FirstName Lunghezza
Larry 400
Geoffrey 400
Alexa 100
Colleen 100
BirthDate
13/04/1977
13/05/1977
13/06/1977
....
15/04/1980
16/04/1947
13/04/1976
...
13/04/1976
13/04/1976
13/04/1976
...
13/04/1990
13/04/1934
...
BirthDate lunghezza
13/04/1977 1
13/05/1977 1
13/06/1977 1
....
15/04/1980 1
16/04/1947 1
13/04/1976 1
...
13/04/1976 1
13/04/1976 1
13/04/1976 1
...
13/04/1990 1
13/04/1934 1
...
Le date cambiano così di frequente che se provassi a comprimerla avrei su lunghezzatutti 1 e otterrei una tabella più grande dell’originale. Vertipaq lascia l’originale.
#sqlsat589February 25th, 2017
Run Length Encoding (RLE) - 1 livello
Vertipaq non usa mai più memoria rispetto alla colonna sorgente…se non riesce a comprimerla la lascia come è
Vertipaq durante il processing di un tabella
Divide la tabella in colonne
Comprime ogni colonna con RLE
Obbiettivo 1 L’ordinamento delle colonne è il punto più importante per RLE (se ne occupa vertipaq ) buon ordinamento = buona compressione
Obbiettivo 2 : Se la dimensione della colonna in memoria è bassa lo scan sarà più veloce
#sqlsat589February 25th, 2017
Dictionary encoding - 2 livello
Conoscendo i possibili valori della stringa utilizzo il numero minimo di bit per rappresentarla. In questo caso 4 possibili valori bastano 2 bit.
Creo il dizionario
Quarter
Q1
Q4
Q1
...
Q2
Q3
Q1
...
Q3
Q3
Q2
...
Q1
Q1
....
DISTINCT
Indice Quarter
1 Q1
2 Q2
3 Q3
4 Q4
Quarter
1
1
1
...
2
2
2
...
3
3
3
...
4
4
....
SOSTITUISCI
RLE
Quarter Count Lunghezza
1 1 400
2 400 400
3 800 100
4 900 100
xVelocity storage
Con il dictionary encoding Vertipaq è datatyping independent. Non ha nessuna importanza il tipo dei campi che si utilizzano nelle viste per popolare il modello
Indice Quarter
1 Q1
2 Q2
3 Q3
4 Q4
Ve
rsio
ne c
om
pre
ssa
Diz
ion
ario
#sqlsat589February 25th, 2017
Conclusioni su RLE e Dictionary encoding
Una stringa nella tabella dei fatti (osceno) non ha più nessun prezzo grazie al dictionary encoding
Obbiettivo 1: Importa solo il numero di valori distinti delle colonne
Tanti valori distinti occupano più spazio (+ RAM) ed più lungo a fare analisi
Pochi valori distinti occupano poco spazio (- RAM) e tutte operazioni ridotte
#sqlsat589February 25th, 2017
Long Scan Time: Spesso per aggregazioni semplici le query DAX fannolo scan su una o piu colonne. Il costo di questa scan dipende dalladimensione delle colonne che dipende dal numero di valori distinti eloro distribuzione
Large Cardinality: Un largo numero di valori univoci in una colonna puòdare noia alla DISTINCTCOUNT
Alta frequenza di CallbackDataID: Un largo numero di chiamate dallostorage engine al formula engine possono influire pesantemente sulleperformance
Large Materializzation: Se uno Storage Engine produce una grandedatacache la sua generazione richiede tempo (allocamento di RAM)
Cause dei bottlenecks nello storage engine
#sqlsat589February 25th, 2017
Demo 0
#sqlsat589February 25th, 2017
Demo 0
La sum è sensibile alla dimensione perchè deve fare lo scan della tabella quindi deve fare lo scan di tutte le colonne
La distinctcount dipende dalla cardinalità
N.B. Ridurre il numero di valori distinti velocizza le query
Colonna Memoria (MB) Valori distinti SUM DISTINCTCOUNT
Sales Amount 1,855,587,152 40,000 809 2023
TimeKey 1,237,296,936 86,400 526 2556
#sqlsat589February 25th, 2017
Demo 1
Eseguiamo la seguente formula DAX
Genera un query plan che con due scansioni due coppie di Vertipaq ScanSQL Profiler DAX Studio
#sqlsat589February 25th, 2017
Demo 1 – Perchè due query SE?
1° Vertiaq Scan estrae CalendarYear da Date e la somma di SalesAmount da Internet Sales. Usa solo SE perchè sono operazioni che sa fare
Se la prima query risolve tutto perchè c’è una 2° Internal Vertiaq Scan?
La seconda restituisce gli anni e la prima le vendite e anni e poi mettoassieme con FE
#sqlsat589February 25th, 2017
Demo 1 – Considerazioni sull’ottimizzazione
Recupera gli anni dalla tabella dei fatti
Che senso ha fare la scansione della tabella dei fatti per gli anni?
Secondo voi quale è la maniera più veloce per recuperare tutte le date?
Analizzando la tabella dei fatti (77.309.440 rows)
Analizzando la tabella della dimensione Date (3652 rows)
#sqlsat589February 25th, 2017
Demo 2 – SUMMARIZE vs ADDCOLUMNS
Con la nuova query si azzera il tempo per recuperare l’anno
SQL Profiler DAX Studio
#sqlsat589February 25th, 2017
Demo 2 – SUMMARIZE vs ADDCOLUMNS
Con la SUMMURIZE al posto di VALUE peggioro le performance ma scrivomeno DAX
E se uso SUMMARIZECOLUMNS (Dax 2015) ?
#sqlsat589February 25th, 2017
Una summarize dove aggreghiamo sia per anno che per colore.
2° Vertipaq Scan per recuperare anno e colore fa uno scan su tabella fatti
Demo 3 – Problema SUMMARIZE con più colonne
SQL Profiler DAX Studio
#sqlsat589February 25th, 2017
Demo 3 – Soluzione
Utilizzamo la ADDCOLUMNS con CROSSJOIN per ottimizzare la formula
Le Vertipaq Scan aumentano da 2 a 3 perchè viene eseguita unaInternal Vertipaq Scan secca sulla tabella prodotti e calendario
SQL Profiler DAX Studio
#sqlsat589February 25th, 2017
Con ROLLUP possiamo ottenere il venduto per anno e colore , il totaleper anno e colore e il grand total per anno.
Ci sono due modi di operare:
Generazione di più query SE per recuperare i sottototali e per il grand total(l’unica possibile)
Recuperare il dettaglio e poi aggregare all’interno di FE per (questo solo se sonosicuro che sono additive)
Demo 4 – ROLLUP
#sqlsat589February 25th, 2017
Demo 4 – ROLLUP
Come si vede il numero di query SE è aumentato di molto
la ROLLUP aumenta la complessità di (2N + 1) volte (N n° parametri)(subtotali su 2 livelli =>2n+1=5 scansioni, 3 livelli =>3n+1=7 scansioni...)
SQL Profiler DAX Studio
#sqlsat589February 25th, 2017
Esaminiamo la seguente query DAX
I callbackDataID sono richieste di aiuto di SE a FE inquanto non sa fare IF e chiede a FE di eseguirlo.Funziona ma ci sono due problemi:
uno è multi-thread e l’altro no
si parla di elaborazione di FE e quindi non si usa la cache
Demo 5 – CallbackDataID
#sqlsat589February 25th, 2017
Demo 5 – CallbackDataID
Anche se uso DIVIDE ho sempre la callbackID anche se è un pò piùveloce
#sqlsat589February 25th, 2017
Demo 5 – CallbackDataID
Riscriviamo la formula per levare la CallBackDataID
#sqlsat589February 25th, 2017
La SUMX non si comporta come una iterazione perchè viene eseguitadirettamente da Vertipaq in quanto la sa gestire
Demo 5 – CallbackDataID non avviene con le interazioni singole
#sqlsat589February 25th, 2017
doppia iterazione genera un CallbackDataID
Demo 5 – CallbackDataID avviene con le interazioni annidate
#sqlsat589February 25th, 2017
Vogliamo ottenere i 50 prodotti che hanno vendite maggiori
Demo 6 – Riduciamo la materializzazione
Dobbiamo ridurrela dimensione delladatacache che inquesto caso è di 79KB
#sqlsat589February 25th, 2017
Dobbiamo ridurre la dimensione della Datacache
Demo 6 – Riduciamo la materializzazione
#sqlsat589February 25th, 2017
Capire come funzionano SE e FE
Ridurre FE, aumentare SE
Leggere i query plan rende possibile l’ottimizzazione
DAX non è facile da ottimizzare.... Ma è meglio che con MDX
Libro di riferimento da cui partire
https://www.sqlbi.com/books/the-definitive-guide-to-dax/
Link di riferimento per approfondire
http://www.sqlbi.com/wp-content/uploads/DAX-Query-Plans.pdf
http://www.sqlbi.com/wp-content/uploads/Understanding-Distinct-Count-in-DAX-Query-Plans.pdf
Conclusioni
#sqlsat589February 25th, 2017
THANKS! Q&A
#sqlsat589