Optimizing dax

44
#sqlsat589 February 25th, 2017 Optimizing DAX Marco Pozzan

Transcript of Optimizing dax

Page 1: Optimizing dax

#sqlsat589February 25th, 2017

Optimizing DAX

Marco Pozzan

Page 2: Optimizing dax

#sqlsat589February 25th, 2017

Sponsor

Page 3: Optimizing dax

#sqlsat589February 25th, 2017

Organizers

Page 4: Optimizing dax

#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

[email protected]

@marcopozzan.it

www.marcopozzan.it

http://www.scoop.it/u/marco-pozzan

http://paper.li/marcopozzan/1422524394

Page 5: Optimizing dax

#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

Page 6: Optimizing dax

#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)

Page 7: Optimizing dax

#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)

Page 8: Optimizing dax

#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

Page 9: Optimizing dax

#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

Page 10: Optimizing dax

#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

Page 11: Optimizing dax

#sqlsat589February 25th, 2017

Profiler SQL Server

DAX Studio (https://daxstudio.codeplex.com/)

Tool per le ottimizzazioni

Page 12: Optimizing dax

#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

Page 13: Optimizing dax

#sqlsat589February 25th, 2017

Vediamo come viene risolta questa query

SQL Profiler

DAX Studio

Come lavorano?

Page 14: Optimizing dax

#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

Page 15: Optimizing dax

#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

Page 16: Optimizing dax

#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

Page 17: Optimizing dax

#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

Page 18: Optimizing dax

#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

Page 19: Optimizing dax

#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

Page 20: Optimizing dax

#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.

Page 21: Optimizing dax

#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

Page 22: Optimizing dax

#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

Page 23: Optimizing dax

#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

Page 24: Optimizing dax

#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

Page 25: Optimizing dax

#sqlsat589February 25th, 2017

Demo 0

Page 26: Optimizing dax

#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

Page 27: Optimizing dax

#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

Page 28: Optimizing dax

#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

Page 29: Optimizing dax

#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)

Page 30: Optimizing dax

#sqlsat589February 25th, 2017

Demo 2 – SUMMARIZE vs ADDCOLUMNS

Con la nuova query si azzera il tempo per recuperare l’anno

SQL Profiler DAX Studio

Page 31: Optimizing dax

#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) ?

Page 32: Optimizing dax

#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

Page 33: Optimizing dax

#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

Page 34: Optimizing dax

#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

Page 35: Optimizing dax

#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

Page 36: Optimizing dax

#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

Page 37: Optimizing dax

#sqlsat589February 25th, 2017

Demo 5 – CallbackDataID

Anche se uso DIVIDE ho sempre la callbackID anche se è un pò piùveloce

Page 38: Optimizing dax

#sqlsat589February 25th, 2017

Demo 5 – CallbackDataID

Riscriviamo la formula per levare la CallBackDataID

Page 39: Optimizing dax

#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

Page 40: Optimizing dax

#sqlsat589February 25th, 2017

doppia iterazione genera un CallbackDataID

Demo 5 – CallbackDataID avviene con le interazioni annidate

Page 41: Optimizing dax

#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

Page 42: Optimizing dax

#sqlsat589February 25th, 2017

Dobbiamo ridurre la dimensione della Datacache

Demo 6 – Riduciamo la materializzazione

Page 43: Optimizing dax

#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

Page 44: Optimizing dax

#sqlsat589February 25th, 2017

THANKS! Q&A

#sqlsat589