MDX – Count of Filtered CROSSJOIN – Problèmes de performance

CONTEXTE: J'utilise MDX depuis un petit moment mais je ne suis en aucun cas un expert en la matière – à la search d'une aide à la performance. Je travaille sur un set de mesures calculées «nombre de magasins autorisés / en stock / vente / Etc» (MDX) dans un cube SQL Server Analysis Services 2012. J'ai réalisé ces calculs correctement à l'origine, mais j'ai découvert qu'ils ne se regroupaient pas dans ma hiérarchie de produits comme je le souhaitais. Les deux hiérarchies principalement utilisées dans ce rapport sont Business -> Item et Division -> Store.

Par exemple, dans les calculs MDX d'origine, la mesure Magasins en stock s'exécuterait correctement au niveau "Article", mais n'inclurait pas une sum appropriée au niveau "Entreprise" situé au-dessus. Au niveau de l'entreprise, nous voulons voir le nombre total de combinaisons magasin / produit en stock, et non pas une valeur distincte ou MAX comme elle semblait le faire à l'origine.

RÉSULTATS D'INTERROGATION ORIGINAUX: Voici un exemple qui ne fonctionne PAS correctement (imaginez qu'il s'agit d'un tableau croisé dynamic Excel):

[FILTER: CURRENT WEEK DAYS] [BUSINESS] [AUTH. STORES] [STORES IN-STOCK] [% OF STORES IN STOCK] [+] Business One 2,416 2,392 99.01% [-] Business Two 2,377 2,108 93.39% -Item 1 2,242 2,094 99.43% -Item 2 2,234 1,878 84.06% -Item 3 2,377 2,108 88.68% -Item N ... ... ... 

RÉSULTATS DE CHERCHER FIXE: Après beaucoup d'essais et d'erreurs, je suis passé à utiliser un count filtré d'un CROSSJOIN () des deux hiérarchies en utilisant la fonction DESCENDANTS (), qui a donné les nombres corrects (ci-dessous):

 [FILTER: CURRENT WEEK DAYS] [BUSINESS] [AUTH. STORES] [STORES IN-STOCK] [% OF STORES IN STOCK] [+] Business One 215,644 149,301 93.90% [-] Business Two 86,898 55,532 83.02% -Item 1 2,242 2,094 99.43% -Item 2 2,234 1,878 99.31% -Item 3 2,377 2,108 99.11% -Item N ... ... ... 

QUESTION QUI A BESOIN D'AIDE: Voici la "nouvelle" requête qui donne les résultats ci-dessus:

 CREATE MEMBER CURRENTCUBE.[Measures].[Num Stores In-Stock] AS COUNT( FILTER( CROSSJOIN( DESCENDANTS( [Product].[Item].CURRENTMEMBER, [Product].[Item].[UPC] ), DESCENDANTS( [Division].[Store].CURRENTMEMBER, [Division].[Store].[Store ID] ) ), [Measures].[Inventory Qty] > 0 ) ), FORMAT_STRING = "#,#", NON_EMPTY_BEHAVIOR = { [Inventory Qty] }, 

Cette syntaxe de requête est utilisée dans un tas d'autres mesures calculées dans le cube, avec seulement une variation de la condition [Quantité d'inventaire] en bas ou en enchaînant des conditions supplémentaires. .

Dans son état actuel, cette requête peut prendre 2-3 minutes, ce qui est beaucoup trop long pour l'audience de ce rapport. Quelqu'un peut-il penser à un moyen de réduire la charge de la requête ou de m'aider à réécrire cela pour être plus efficace?

Je vous remercie!


MISE À JOUR 24/02/2014: Nous avons résolu ce problème en ignorant une grande partie du MDX impliqué et en ajoutant des valeurs d'indicateur à notre requête nommée dans le DSV.

Par exemple, au lieu de faire une command de filter dans le code MDX pour "nombre de magasins vendant" – nous avons simplement ajouté ceci à la table de faits nommée requête …

 CASE WHEN [Sales Qty] > 0 THEN 1 ELSE NULL END AS [Flag_Selling] 

… alors nous avons simplement agrégé ces mesures comme LastNonEmpty dans le cube. Ils roulent beaucoup plus vite que les requêtes MDX complètes.

Il devrait être beaucoup plus rapide de modéliser vos conditions dans le cube, en évitant la fonction lente du Filter :

S'il n'y a qu'une poignée de conditions, ajoutez un atsortingbut pour chacune d'entre elles avec deux valeurs, une pour la condition remplie, dites "cond: oui", et une pour la condition non remplie, dites "cond: non". Vous pouvez le définir dans une vue de la table des faits physiques ou dans le DSV, ou vous pouvez le modéliser physiquement. Ces attributes peuvent être directement ajoutés à la table des faits, en définissant une dimension sur la même table, ou plus simplement en tant que table de dimension distincte référencée à partir de la table de faits. Puis définissez votre mesure comme

 CREATE MEMBER CURRENTCUBE.[Measures].[Num Stores In-Stock] AS COUNT( CROSSJOIN( DESCENDANTS( [Product].[Item].CURRENTMEMBER, [Product].[Item].[UPC] ), DESCENDANTS( [Division].[Store].CURRENTMEMBER, [Division].[Store].[Store ID] ), { [Flag dim].[cond].[cond: yes] } ) ) 

Éventuellement, vous pourriez même définir la mesure comme une mesure de comptage standard de la table de faits.

Dans le cas où il existe plusieurs conditions, il peut être judicieux d'append un seul atsortingbut avec une valeur pour chaque condition en tant que relation plusieurs-à-plusieurs. Ce sera légèrement plus lent, mais toujours plus rapide que l'appel du Filter .

Je crois que vous pouvez éviter la jointure croisée ainsi que filterr complètement. Essayez d'utiliser ceci:

 CREATE MEMBER CURRENTCUBE.[Measures].[Num Stores In-Stock] AS CASE WHEN [Product].[Item Name].CURRENTMEMBER IS [Product].[Item Name].[All] THEN SUM(EXISTS([Product].[Item Name].[Item Name].MEMBERS,[Business].[Business Name].CURRENTMEMBER), COUNT( EXISTS( [Division].[Store].[Store].MEMBERS, ( [Business].[Business Name].CURRENTMEMBER, [Product].[Item Name].CURRENTMEMBER ), "Measure Group Name" ) )) ELSE COUNT( EXISTS( [Division].[Store].[Store].MEMBERS, ( [Business].[Business Name].CURRENTMEMBER, [Product].[Item Name].CURRENTMEMBER ), "Measure Group Name" ) ) END 

Je l'ai essayé en utilisant une dimension dans mon cube et en utilisant la hiérarchie Area-Subsidiary. L'instruction case gère la situation de visualisation des données au niveau Business. Fondamentalement, le SUM() travers tous les membres des noms d'éléments utilisés dans l'instruction CASE calcule des valeurs pour les noms d'éléments individuels, puis résume toutes les valeurs. Je crois que c'est ce dont tu avais besoin.