saiku mdx performance issues with * operator for crossjoin - mdx

Can anyone explain why
SELECT
NON EMPTY {Hierarchize({[Measures].[Quantity]})} ON COLUMNS,
NON EMPTY ([Time].[Years].Members * [Markets].[City].Members * [Product].[Product].Members * [Customers].[Customer].Members) ON ROWS
FROM [SteelWheelsSales]
is so much slower than this:
SELECT
NON EMPTY {Hierarchize({[Measures].[Quantity]})} ON COLUMNS,
NON EMPTY CrossJoin([Time].[Years].Members, CrossJoin([Markets].[City].Members, CrossJoin([Product].[Product].Members, [Customers].[Customer].Members))) ON ROWS
FROM [SteelWheelsSales]
I would like to use the * operator to make crossjoins but it seems so much slower. Any idea why and what can I do?

Seems like the order is important:
http://community.altiusconsulting.com.ourwindowsnetwork.com/blogs/altiustechblog/archive/2008/06/13/mdx-crossjoin-performance.aspx
Just in case the above link dies in the future it basically compares the two following AdvWks scripts performance:
QUERY 1
WITH MEMBER Measures.PerfmonTest AS
Count(
Crossjoin( [Promotion].[Promotions].[Promotion] ,
Filter([Customer].[Customer Geography].[Customer], RIGHT([Customer].[Customer Geography].CurrentMember.Name,5) = "Smith")
)
)
SELECT Measures.PerfmonTest ON Columns
FROM [Adventure Works]
QUERY 2
WITH MEMBER Measures.PerfmonTest AS
Count(
Crossjoin(
Filter([Customer].[Customer Geography].[Customer], RIGHT([Customer].[Customer Geography].CurrentMember.Name,5) = "Smith")
,[Promotion].[Promotions].[Promotion] )
)
SELECT Measures.PerfmonTest ON Columns
FROM [Adventure Works]

Related

custom count measure runs forever MDX

So this question goes off the one here
I've been trying to do a similar count measure and I did the suggested solution but it's still running.... and it's been more than 30 minutes with no results, while without that it runs in under a minute. So am I missing something? Any guidance would help. Here is my query:
WITH
MEMBER [Measures].[IteractionCount] AS
NONEMPTY
(
FILTER
(
([DimInteraction].[InteractionId].[ALL].Children,
[Measures].[Impression Count]),
[DimInteraction].[Interaction State].&[Enabled]
)
).count
SELECT
(
{[Measures].[IteractionCount],
[Measures].[Impression Count]}
)
ON COLUMNS,
(
([DimCampaign].[CampaignId].[CampaignId].MEMBERS,
[DimCampaign].[Campaign Name].[Campaign Name].MEMBERS,
[DimCampaign].[Owner].[Owner].MEMBERS)
,[DimDate].[date].[date].MEMBERS
)
ON ROWS
FROM
(
SELECT
(
{[DimDate].[date].&[2020-05-06T00:00:00] : [DimDate].[date].&[2020-05-27T00:00:00]}
)
ON COLUMNS
FROM [Model]
)
WHERE
(
{[DimCampaign].[EndDate].&[2020-05-27T00:00:00]:NULL},
[DimCampaign].[Campaign State].&[Active],
{[DimInteraction].[End Date].&[2020-05-27T00:00:00]:NULL}//,
//[DimInteraction].[Interaction State].&[Enabled]
)
I don't know if FILTER is affecting it in any way but I tried it with and without and it still runs forever. I do need it specifically filtered to [DimInteraction].[Interaction State].&[Enabled]. I have also tried to instead filter to that option in the WHERE clause but no luck
Any suggestions to optimize this would be greatly appreciated! thanks!
UPDATE:
I end up using this query to load data into a python dataframe. Here is my code for that. I used this script for connecting and loading the data. I had to make some edits to it though to use windows authentication.
ssas_api._load_assemblies() #this uses Windows Authentication
conn = ssas_api.set_conn_string(server='server name',db_name='db name')
df = ssas_api.get_DAX(connection_string=conn, dax_string=query))
The dax_string parameter is what accepts the dax or mdx query to pull from the cube.
Please try this optimization:
WITH
MEMBER [Measures].[IteractionCount] AS
SUM
(
[DimInteraction].[InteractionId].[InteractionId].Members
* [DimInteraction].[Interaction State].&[Enabled],
IIF(
IsEmpty([Measures].[Impression Count]),
Null,
1
)
)
SELECT
(
{[Measures].[IteractionCount],
[Measures].[Impression Count]}
)
ON COLUMNS,
(
([DimCampaign].[CampaignId].[CampaignId].MEMBERS,
[DimCampaign].[Campaign Name].[Campaign Name].MEMBERS,
[DimCampaign].[Owner].[Owner].MEMBERS)
,[DimDate].[date].[date].MEMBERS
)
PROPERTIES MEMBER_CAPTION
ON ROWS
FROM
(
SELECT
(
{[DimDate].[date].&[2020-05-06T00:00:00] : [DimDate].[date].&[2020-05-27T00:00:00]}
)
ON COLUMNS
FROM [Model]
)
WHERE
(
{[DimCampaign].[EndDate].&[2020-05-27T00:00:00]:NULL},
[DimCampaign].[Campaign State].&[Active],
{[DimInteraction].[End Date].&[2020-05-27T00:00:00]:NULL}//,
//[DimInteraction].[Interaction State].&[Enabled]
)
CELL PROPERTIES VALUE
If that doesn’t perform well the please describe the number of rows returned by your query when you comment out IteractionCount (sic) from the columns axis. And please describe how many unique InteractionId values you have.

Pentaho Mondrian- Hide a dimension value from a role

I am using Pentaho Mondrian to build a billing cube with the dimensions "country" and "reference".
To one of my roles, I just want to show the reference value when country is equal to "Brazil". If it is not Brazil, reference should be null.
How it is:
http://i.stack.imgur.com/yipPJ.png
How it should be:
http://i.stack.imgur.com/PoF2w.png
How can I do this?
I tryed to use a calculated member with CASE WHEN, but it didn´t work.
Should I use IIF instead?
I code this, but it is not working too:
WITH
MEMBER [dim_reference.Reference].[reference].Members AS
IIF
(
[dim_country.country].[country].CurrentMember = 'Brazil'
,[dim_reference.Reference].[reference].MEMBERS
,''
)
SELECT
NON EMPTY
{Hierarchize({[dim_country.country].[country].MEMBERS})} ON COLUMNS
,NON EMPTY
Order
(
{
Hierarchize({[dim_reference.Reference].[reference].MEMBERS})
}
,[dim_reference.Reference].CurrentMember.Name
,BASC
) ON ROWS
FROM [billing_entry];
Does someone knows how to do this?
A few pointers:
1
So you need to use the IS operator if you want to check for equality with a member.
Rather than this:
[dim_country.country].[country].CurrentMember = 'Brazil'
You use the following - you might need to amend the RHS with the exact full name of your Brazil member:
[dim_country.country].[country].CurrentMember
IS [dim_country.country].[country].[country].[Brazil]
2
Rather than using '' you should use NULL.
Rather than this:
IIF(
<condition>
,<if condition true>
,''
)
You should use this:
IIF(
<condition>
,<if condition true>
,NULL
)
3
You're correct to use IIF rather than CASE if at all possible - IIF generally performs better.
From your screenshots it looks to me that you want Countries ON ROWS rather than ON COLUMNS:
SELECT
NON EMPTY
{} ON COLUMNS
,NON EMPTY
[dim_country.country].[country].MEMBERS ON ROWS
FROM [billing_entry];
Now using SSAS against the AdvWrks cube I can do this:
WITH
MEMBER [Measures].[X] AS
IIF
(
[Customer].[Customer Geography].CurrentMember
IS
[Customer].[Customer Geography].[Country].&[Australia]
,[Product].[Product Categories].CurrentMember.Name
,null
)
SET [s] AS
[Customer].[Customer Geography].[Country]
*
[Product].[Product Categories].[category]
MEMBER [Product].[Product Categories].[All].[calc] AS
[Product].[Product Categories].CurrentMember.Name
SELECT
{[Measures].[X]} ON 0
,[s] ON 1
FROM [Adventure Works];
Which results in this:

MDX Query - Select Columns From Same Dimensions

I have a requirement displaying data from same dimension in more than 1 column. For eg. I want to show data Year and Month wise. In my dimension structure, Year and Month belongs to same hierarchy. When I run below query I get error. PFB the query.
Select NON EMPTY {[Measures].[Target Actual Value]} ON 0,
NON EMPTY {[Realization Date].[Hierarchy].[Year Name].Members *
[Realization Date].[Hierarchy].[Month Year]} ON 1
From [Cube_BCG_OLAP]
The error I get is Query (2, 12) The Hierarchy hierarchy is used more than once in the Crossjoin function. I am new to MDX queries. Please help in this regard. Thanks in advance.
Select NON EMPTY {[Measures].[Target Actual Value]} ON 0,
NON EMPTY {[Realization Date].[Hierarchy].[Year Name].Members ,
[Realization Date].[Hierarchy].[Month Year]} ON 1
From [Cube_BCG_OLAP]
Instead of CROSSJOIN have a set as above. In a set, you can put members from same hierarchy
I like Sourav's answer - but it will put the results in one column which is slightly different than the question.
In AdvWorks this is in one column:
SELECT
[State-Province].MEMBERS ON COLUMNS
,{
[Date].[Calendar].[Calendar Year].MEMBERS
,[Date].[Calendar].[Month].MEMBERS
} ON ROWS
FROM [Adventure Works];
It is possible to switch to two columns and use a cross join but you need to find out the details of your Date dimensions Attribute hierarchies (as opposed to User hierarchies):
SELECT
[State-Province].MEMBERS ON COLUMNS
,
[Calendar Year].[All Periods].Children
* [Month].MEMBERS ON ROWS
FROM [Adventure Works];
In your cube maybe something like this:
SELECT
NON EMPTY
{[Measures].[Target Actual Value]} ON 0
,NON EMPTY
[Year Name].MEMBERS
*
[Month Year].MEMBERS ON 1
FROM [Cube_BCG_OLAP];

Change Dates to numbers

This is the script:
SELECT
{[Measures].[Internet Order Count]} ON COLUMNS
,Descendants
(
[Date].[Calendar].[Month].[August 2006]
,[Date].[Calendar].[Date]
,self
) ON ROWS
FROM [Adventure Works];
It returns this:
Can I change the script so that instead of dates it returns integers starting at either 0 or 1 i.e. the first would be 1 the second would be 2 etc.
This adds a counter but I'd like to get rid of the date column:
WITH
MEMBER [Measures].[r] AS
Rank
(
[Date].[Calendar].CurrentMember
,[Date].[Calendar].[Month].[August 2006].Children
)
SELECT
{
[Measures].[r]
,[Measures].[Internet Order Count]
} ON COLUMNS
,[Date].[Calendar].[Month].[August 2006].Children ON ROWS
FROM [Adventure Works];
This will be difficult, as what you have on the rows and columns are sets of tuples of members, either physical or calculated ones.
What you could do of course is this:
WITH Member [Date].[Calendar].[1] AS [Date].[Calendar].[Date].&[20060801]
Member [Date].[Calendar].[2] AS [Date].[Calendar].[Date].&[20060802]
...
Member [Date].[Calendar].[31] AS [Date].[Calendar].[Date].&[20060831]
SELECT
{
[Measures].[Internet Order Count]
} ON COLUMNS
,
{
[Date].[Calendar].[1],
[Date].[Calendar].[2],
...
[Date].[Calendar].[31]
}
ON ROWS
FROM [Adventure Works]
This may be feasible in case you generate the query with a tool.
However, in cases like this, I normally would keep the query like your second query, and just ignore the row headers in the client tool.

Can I reformulate this MDX query to use sets instead of an "And"?

with member [Measures].[BoughtDispenser] as
Sum(Descendants([Customer].[Customer].CurrentMember, [Customer].[Customer]),
Iif(
(IsEmpty(([Item].[ItemNumber].&[011074], [Measures].[Sale Amount]))
And IsEmpty(([Item].[ItemNumber].&[011069], [Measures].[Sale Amount]))
)
Or IsEmpty([Measures].[Sale Amount]),
0 , 1
)
)
select
{[Measures].[Sale Amount]} on columns,
non empty filter([Customer].[Customer].children, [Measures].[BoughtDispenser])
* {[Item].[ItemNumber].members}
on rows
from [Sales]
where [EnteredDate].[Quarter].&[2010-01-01T00:00:00]
;
The object is to show all the items purchased by customers who also bought either of the two dispensers (011069 and 011074).
I based the calculated member on a query I found to do basket analysis. I feel like there should be a way to write it with the set {[Item].[ItemNumber].&[011074], [Item].[ItemNumber].&[011069]} instead of the two IsEmpty tests. Everything I've tried ended up having every Customer in the result.
My environment is SQL Server Analysis Services 2005.
Yes I can! It just required a slightly different approach to the calculated member:
with member [Measures].[BoughtDispenser] as
Sum(Descendants([Customer].[Customer].CurrentMember, [Customer].[Customer])
* {[Item].[ItemNumber].&[011069], [Item].[ItemNumber].&[011074]},
[Measures].[Quantity Shipped]
)
select
{[Measures].[Sale Amount]} on columns,
non empty filter([Customer].[Customer].children, [Measures].[BoughtDispenser])
* {[Item].[ItemNumber].members}
on rows
from [Sales]
where [EnteredDate].[Quarter].&[2010-01-01T00:00:00]
;