versione italiana versione italiana
english version english version

Prestazioni query MDX

Analysis Services richiede che il client si connetta attraverso il PivotTable Service (PTS), che offre un motore multidimensionale locale e una cache “intelligente”. Il PTS consente di risolvere una query globalmente o parzialmente sul client: la decisione su dove la query MDX sarà risolta è per default affidata allo stesso PTS, che valuta una serie di fattori. Talvolta, però, la sofisticazione di PTS risulta controproducente dal punto di vista dei tempi di risposta.

Da un punto di vista teorico, la risoluzione di una query sul client dovrebbe diminuire il traffico di rete e il carico di lavoro (in termini di CPU) sul server. Tali promesse sono mantenute se la query eseguita sul client non necessita di richiedere dati al server, perché può risolvere la richiesta con i soli dati già in cache. In alcune condizioni, invece, la query è risolta sul client anche quando questo non dispone di tutti i dati necessari, girando così la richiesta al server.

Quando i cubi non sono grandi e soprattutto quando non ci sono dimensioni molto numerose (con almeno decine di migliaia di membri), le differenze sono impercettibili, ma quando il gioco si fa duro ecco che possono emergere grosse differenze. I principali effetti visibili di una query “pesante” risolta sul client sono i seguenti

  • Traffico di rete: il client potrebbe richiedere al server i membri non visibili nel risultato di alcune dimensioni, per effettuare calcoli intermedi, oppure potrebbe richiedere dei dati di base da aggregare sul client.
  • Memoria: il client ha bisogno di memoria per ospitare i dati ricevuti dal server ed effettuare le opportune elaborazioni.
  • CPU: il client consuma CPU per fare dei calcoli in locale.

Ecco che quindi abbiamo un sistema empirico ma efficace per valutare se una query MDX particolarmente lenta è eseguita sul client: analizzando anche solo con Task Manager la CPU e la memoria virtuale del processo (colonna VM Size o Memoria Virtuale, da non confondere con Mem Usage o Utilizzo Memoria) e controllando il traffico di rete si può capire se il tempo di attesa è causato da un’attività del client o no. Se il client non mostra attività apparente significa che la query è risolta sul server, mentre in caso contrario è probabile che la query sia risolta sul client, specialmente se il risultato finale è costituito da un numero di righe e colonne limitato.

La stringa di connessione

Bene, una volta stabilito che la risoluzione di una query sul client non è cosa gradita, cosa si può fare? Agendo sulla stringa di connessione, con il parametro Execution Location si può stabilire che la query va obbligatoriamente risolta sul client. Negli esempi che seguono, immaginiamo di connetterci a un server chiamato OLAPSERVER. La stringa di connessione standard è costituita dal solo nome del server:

OLAPSERVER

Aggiungendo il parametro Execution Location col valore 3 (per forzare il client), la stringa di connessione diventa:

OLAPSERVER; Execution Location=3

Questa stringa può essere usata anche facendo la connessione con un client standard come Excel. A questo punto in teoria l’articolo sarebbe finito, ma purtroppo ci sono un paio di casi in cui, nonostante il parametro Execution Location, la query continua a essere risolta sul client.

Nel caso in cui il client abbia delle impostazioni internazionali diverse da quelle del server, alcune caratteristiche funzionali (confronti e ordinamento) non sono compatibili e per alcune espressioni MDX diventa necessario risolvere la query sul client per garantire il risultato corretto. In realtà, spesso questa differenza non avrebbe effetti sui risultati di una query, ma il PTS non può saperlo. Per obbligarlo a risolvere la query sul server è necessario richiedere di risolvere l’operazione usando delle impostazioni internazionali (in gergo Locale ID, o LCID) corrispondenti a quelle impostate sul server. Il parametro da usare questa volta è Locale Identifier. Ipotizzando che il server abbia le impostazioni statunitensi (LCID 1033), la stringa di connessione diventa:

OLAPSERVER; Execution Location=3; Locale Identifier=1033

Ricordiamo che il locale ID per l’Italia è 1040. Un elenco dei LCID disponibili è facilmente reperibile in molte fonti, per esempio sul sito di MSDN: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/script56/html/vsmsclcid.asp.

Infine, c’è un ultimo parametro che possiamo aggiungere per garantire l’esecuzione sul server, che è Default Isolation Mode. Se ha un valore diverso da 0 stabilisce che il livello di isolamento dell’operazione sia Serializable, ignorando la richiesta fatta dal rowset OLE DB. Per le nostre esigenze, il valore deve essere 1.

OLAPSERVER; Execution Location=3; Default Isolation Mode=1; Locale Identifier=1033

La stringa di connessione appena vista garantisce l’esecuzione di una query MDX sul server (a patto che quest’ultimo abbia LCID pari a 1033).

Considerare altre ottimizzazioni di MDX

Per concludere, ricordiamo che diverse query MDX possono dare “quasi” lo stesso risultato, ma con tempi di esecuzione diversi. Un tipico esempio è la differenza tra la clausola NON EMPTY su un asse dei risultati e l’uso della funzione MDX NonEmptyCrossJoin: la prima agisce sul risultato visibile della query, la seconda ignora invece gli effetti dei membri calcolati e valuta solo la presenza di dati originali sul cubo in corrispondenza dei membri richiesti. La NonEmptyCrossJoin ha tipicamente dei tempi di risposta molto più rapidi della NON EMPTY, a patto che le differenze funzionali siano accettabili.

La lezione da trarre è che di fronte a una query con prestazioni non accettabili bisogna comprendere il funzionamento interno della query stessa per individuare eventuali colli di bottiglia o funzioni sostitutive che diano un risultato equivalente ma in tempi più rapidi.