Showing posts with label Analysis Services. Show all posts
Showing posts with label Analysis Services. Show all posts

Wednesday 24 February 2021

Generating Usage Statistics from a SSAS Tabular Cube

Once you have users accessing your cube it’s almost inevitable at some point that someone will ask you to generate usage statistics from it, and there are a number of methods to achieve this. In this quick blog post, I’ll detail them and my experiences with each, and then use this data to create a PBI report.

 

Native Tabular Properties

The first method is natively through the tabular cube properties. This also has the added bonus (read impact) that it will optimise future aggregations based on usage – in fact that’s its main purpose.

This can be done by setting the CreateQueryLogTable to true, setting up the QueryLogConnectionString (to point to the DB where the usage table requires hosting), setting the QueryLogSamping rate (10 means every 10th query will be logged), and finally the name of the QueryLog table.

SQL Server Analysis Services Query Log Related Properties

Advantages of this method is that its very easy to setup with limited knowledge required and it could potentially improve performance if you have an environment where users submit repetitive queries. Unfortunately there are also a number of disadvantages which led me to find other methods. Firstly, it creates a degree of overhead on the cube if its sampling too often; we actually had visible performance related complaints once we turned it on – either through the sampling or change to the “optimised” aggregations. Depending on the sampling rate, you could also find that users who rarely use the cube are not picked up as part of the stats.  As well as this any changes to the cube structure will cause the logging table to be reset. The table is also limited in terms of what it actually logs (as you can see below) – useful if you just want just the user and timestamp info but not much else, and no real ability to configure.

Query the OlapQueryLog table for Cube activity

 

AS Trace

To that extent, I looked for other tools to do the same task but better and I found AS Trace.

Originally built for SQL Server 2012, it works fine on 2014 – and provides you the ability to run a trace against the cube activities (and log to a table) exactly like the SQL profiler but without the overhead of the GUI which adds unnecessary memory/processor power. It also runs as a windows service allowing it to restart automatically when the server reboots. If this is the case, the tool also logs the existing data to a History table and truncates the logging table. Exactly what I was after.

The tool collects information based on a preconfigured Analysis Services Profiler template, which can be optimised depending on which events you are interested in. I initially ran it using most events selected, and with a limited user set it was generating in the region of 25,000 rows a day. This was clearly not maintainable for a long period of time. I then used the following blog post to understand what each event of the profiler was giving me and then just created a lightweight trace definition file to give me what I wanted. I limited it to Query Begin, Query End (for DAX/MDX statements) and Audit Logon/Logout (for session data).

The setup is very straight forward, just run the install.bat as an escalated privileged account, and check it installs the service correctly. Next, add your SSAS service account to the Logon of the service, make sure the account has “Log on as Service” and membership to the database you are writing to in the form of DDL and DML access, i.e. able to create tables, write to tables – and lastly admin rights to the instance of SSAS you intend to use.

Next, configure the ASTrace.exe.config file with the parameters you want the tool to use. This includes the location of the cube (can handle multiple cubes), the location of the trace definition file, the location of the DB instance and table you want to log to and lastly whether you want to preserve history on restart. The only thing I couldn’t do here, is set the schema of the table it was using to log to, which defaults to dbo.

All that’s left is to start the service, and check the log file to see if it has created any errors on start-up. If not, the table should be created correctly and awaiting input.

I also saw another method while researching using Extended Events (XEvents) but did not implement this once AS Trace provided me with the information I needed.

 

View / Power BI Report

I initially used the data to run a limited set of queries to extract total users, and total queries for a given time period. This was useful to a degree but from the data collected I realised I could be doing so much more.

This lead me to do some analysis across the type of metrics being logged, and allowed me to create a view on top of the tables of what I thought might be useful on a report. I removed all the redundant columns it was tracking, and created some friendly names for the EventSubclass, and other columns. I used the PATINDEX function to check the query statement for existence of some important values – while not an exact science, it would give me a good picture of the split between certain user groups and KPIs being run. I’ve included the view definition below.

I ended up limiting the data to EventClass 10 as this seemed to capture all the necessary data. The only downside I have seen so far is that users querying through the Power BI web service are anonymised under the service account name. I’m currently looking into options to resolve this which I’ve seen as configuration options on Power BI – to allow through the username as long as it can be matched at the other end.

SELECT 
RowNumber AS ID, 
SPID AS SessionID,
CurrentTime AS DateQueried, 
NTUserName AS Username,
CASE EventSubClass 
WHEN 0 THEN 'MDX Query (Excel)' 
WHEN 3 THEN 'DAX Query (Power BI)' 
WHEN 1 THEN 'METADATA Query'
END AS QueryType, 
CASE Success WHEN 1 THEN 'Successful Query' ELSE 'Query Error' END AS SuccessfulQuery,
CONVERT(DECIMAL(10,2),CONVERT(DECIMAL(18,3),CPUTime)/1000) AS CPUTimeSec, 
CONVERT(DECIMAL(10,2),CONVERT(DECIMAL(18,3),Duration)/1000) AS DurationSec, 
TextData AS Query, 
CASE PATINDEX('%Mexico%',TextData) WHEN 0 THEN 0 ELSE 1 END AS MexicoMarket,
CASE PATINDEX('%Colombia%',TextData) WHEN 0 THEN 0 ELSE 1 END AS ColombiaMarket,
CASE PATINDEX('%CS4%',TextData) WHEN 0 THEN 0 ELSE 1 END AS CS4,
ServerName
FROM 
[dbo].[ASTraceTable]
WHERE
EventClass = 10

Once I had the view, creating the report was relatively straight forward, and can be seen below.

I included metrics for number of queries by user (blurred out) which also doubled as a filter, the % split of queries for things such as Excel/Power BI, a measure of queries by timeframe, a logarithmic scaled display for queries by query duration, and lastly a split of queries by KPI. I intend to tweak these once I receive more data from the trace, but was relatively happy with the information that they were providing.

Untitled (002)

Please let me know if you have any comments.

https://adatis.co.uk/generating-usage-statistics-from-a-ssas-tabular-cube/

Saturday 28 December 2019

SSAS Processing Error: Unicode string issue during dimension processing

SSAS and the database engine use different comparison rules depending on the collation, character sets, and handling of blanks in the middle or at the end of a string. This becomes an issue during SSAS processing when key values used to establish attribute relationships must be an exact match. Sometimes, what passes as a ‘match’ in the database engine is seen by SSAS as a non-matching value, resulting in processing errors that can be a challenge to track down if the value happens to be a blank! This article describes the problem in more detail and provides various workarounds.

Actual error (with placeholder values)

Errors in the OLAP storage engine: The attribute key cannot be found when processing: Table: 'MyDimTable', Column: 'Column1', Value: 'alzイ'. The attribute is 'Column1'.
Errors in the OLAP storage engine: The attribute key was converted to an unknown member because the attribute key was not found. Attribute MyDimTableKey of Dimension: MyDimTable from Database: MyDB, Record: 3.
Notice the Unicode value, where the blank terminator is from a Japanese character set. If you get the “attribute key cannot be found” error and the value contain a Unicode blank in the middle or end of the string, you are most likely seeing the effects of these different comparison rules.

Cause:

The problem arises when Analysis Services uses different comparison rules when processing attribute relationships.
By default, the relational database engine uses a width-insensitive collation, such that the following strings are interpreted as equivalent values:
  • string1+<double-byte-blank>+string2
  • string1+<single-byte-blank>+string2
Notice the first member has a double-byte space/blank and the second member has a single-byte space/blank, at the same position in the member name.
If these strings were used as keys to relate rows from different tables, the database engine would recognize these strings as the same value and create the relationship accordingly.
Now suppose that you are processing an Analysis Services database that uses these strings as KeyColumns in an attribute relationship. Unlike the database engine (set to width-insensitive collation), SSAS will interpret these as different strings, generating an error that a matching record cannot be found, and possibly registering one or more of the values as the unknown member.
The attribute key cannot be found because to SSAS, string1+<double-byte-blank>+string2 is not the same as string1+<single-byte-blank>+string2, and therefore fails to meet the criteria used to establish an attribute relationship.

Resolution:

If this behavior is acceptable, then you should do nothing.
However, if want to SSAS to exhibit the same behaviors as the relational database engine, you can use one of the following workarounds:
  • Set ProcessingGroup to ByTable (instead of the default, ByAttribute). This setting is specified in Dimension Designer, in SQL Server Data Tools, on the dimension definition.
  • Set server configuration property | Language/Collation, to be width-sensitive and the dimension definition to be width-sensitive. You can set this in Management Studio, in server properties.
By using either workaround, each string in our example, (string1+<double-byte-blank>+string2 and string1+<single-byte-blank>+string2) would each be considered a viable match for the other (in terms of an attribute relationship), allowing processing to succeed.
Alternatively, you can address the issue in the relational database by changing double-byte spaces to single-byte spaces. See Server-Side Programming with Unicode  . For information about the T-SQL REPLACE function, see http://technet.microsoft.com/en-us/library/ms186862.aspx 

Notes:

Width-insensitive is the default collation for the SQL Server relational engine, so if you are working with global data, you are more likely to run into this issue when processing an Analysis Services database.
DBCS is a double-byte character set. A blank character in DBCS is Unicode 12288 (hex 3000). SBCS is a single-byte character set. A blank character in SBCS is 32. Width-sensitivity on the collation will determine whether these are interpreted as the same or different values, for strings having a trailing blank.






Wednesday 4 September 2013

SSAS – String Storage Calculator

Usually, in an OLAP cube, measures are numeric values and strings are used primarily as descriptions of dimension members.
In Analysis Services, strings are stored in separate structures – called “string stores” – because they have dynamic records size, and are less efficient – much less efficient – than numeric fields.
Furthermore, every string has an overhead of 12 additional bytes for management – so even a 1-byte string takes more room than an 8-byte numeric field.
For these two reasons alone we should limit the use of strings in our projects – that means we should use them only as “user friendly labels” for all dimension members – so, whenever possible, we should prefer integer values.
However, the worst thing about strings in Analysis Services – at least before SQL Server 2012 – is that the string store has an absolute maximum size of 4GB.
This limit applies to every single attribute of every dimension and, more precisely, to any of the following types of string file stores:
  • *.ksstore – Used to store strings representing keys of attribute members
  • *.asstore – Used to store the names of members
  • *.bsstore – Used to store the blobs of members
When one of these files exceeds the 4GB size limit, processing will fail and you will receive – usually after a long time – a message like this:

This is a “physical” limit of the engine, hence there is no workaround and to avoid this problem, you can try one or more of these potential solutions:
  • Do not use strings as key columns for attributes with a large number of members
  • Shorten attributes names
  • Shorten translations of attributes names
  • Switch to a ROLAP dimension
What I am interested to underline here, is that we can avoid spending a lot of time processing a big dimension only to discover at the end that the engine is not able to complete the process because of this problem.
In fact, we can easily estimate the storage needed by our dimension using this simple calculation:
                Total storage = regular storage + overhead storage
Where
                Regular storage = (members * characters * translations * 2)
                Overhead storage = (members * translations * 12)
And
                Members = number of members in our dimension
                Characters = number of characters in the string
                Translations = number of translations including the default language
                2 = constant value for conversion to Unicode characters
                12 = constant value for strings overhead
Here an example:
                2,000,000 members
x 94 characters per member name
x 10 translations
x 2 for conversion to Unicode characters
+
2,000,000 members
x 10 translations
x 12 bytes overhead per string
=
                4,000,000,000 bytes
(We can approximate this value to the maximum limit even if the real value is
1GB = 1,0243 bytes = (1,024 * 1,024 * 1,024) bytes = 1,073,741,824 bytes
4GB = 1,073,741,824 * 4 = 4,294,967,296 bytes)
From the above calculations, it is easy to understand that, with a member name that is 94 characters long and 10 translations, our dimension is limited to 2 million members.
Well, the formula is not so complicated, but surely, it would be easier to have a simple utility to calculate the estimated storage occupation of our dimension attributes.
That was exactly my thought a few days ago when I had to do it a lot of time in a very big project.
Therefore, I decided to develop a very simple application during my – very little indeed – spare time.
I called it “SSAS – String Storage Calculator” and you can download it here:
https://skydrive.live.com/?cid=967b33af45c9c3ba&id=967B33AF45C9C3BA!186&authkey=!AAoVjrObyUX5wkQ

source
http://francescodechirico.wordpress.com/2012/07/04/ssas-string-storage-calculator/







































Friday 9 August 2013

Linked Server for Analysis Services

Following command will create a linked server on your database server instance named “SSASSERVER”.
EXEC master.dbo.sp_addlinkedserver
@server = N'SSASSERVER', -- name of linked server
@srvproduct=N'MSOLAP',
@provider=N'MSOLAP', -- see list of providers available on SQL Server under Linked Server node in SSMS Object Browser
@datasrc=N'ServerName', -- machine or instance name  that host Analysis Services
@catalog=N'CubeDatabase' -- Analysis Services database (cube)



If database server and Analysis Services are on different machines, queries executed through it may have a problem with "double hop" (fact that security context cannot be transferred from one server to the other).

An exception occurred while executing a Transact-SQL statement or batch.
(Microsoft.SqlServer.Connectionlnfo)
Cannot initialize the data source object of OLE DB provider MSOLAP’ For linked server "SSASSERVER",
OLE DB provider “MSOLAP” For linked server “OLAP_AM” returned message “An error was encountered in the transport layer.”.
OLE DB provider “MSOLAP” for linked server “OLAP_AM’ returned message “The peer prematurely closed the connection.”. (Microsoft SQL Server, Error: 7303)
To resolve that problem you have 3 options:
1. Run SQL queries from data server (you need to be remotely connected to the database server)
2. Enable use of Kerberos on the database server
3. Set proxy account for linked server, so that MDX queries are executed in its context instead of in context of the user that is issuing t-sql query:
EXEC master.dbo.sp_addlinkedserver
@server = N'SSASSERVER', -- name of linked server
@srvproduct=N'MSOLAP',
@provider=N'MSOLAP', -- see list of providers available on SQL Server under Linked Server node in SSMS Object Browser
@datasrc=N'ServerName', -- machine or instance name  that host Analysis Services
@catalog=N'SimplifiedCube' -- Analysis Services database (cube)

EXEC master.dbo.sp_addlinkedsrvlogin 
@rmtsrvname=N'SSASSERVER',
@useself=N'False',
@locallogin=NULL,
@rmtuser=N'myDomain\Login',
@rmtpassword='########'



Now you may be able to execute queries using linked server by openquery method.
Select * From OpenQuery(SSASSERVER, 'mdx query')




Friday 19 July 2013

Changing an Analysis Services instance to tabular mode

Say you have already installed an Analysis Services instance of SQL Server 2012. Maybe you made a mistake in setup and accidentally set it up as a multidimensional instance. What do you do?
This is unsupported but it works. You can change the DeploymentMode property in the msmdsrv.ini file to change the mode of the server instance.
Note that you can only run an Analysis Services instance in a single mode at a time. You cannot host multidimensional and tabular databases on the same instance. If you must have both types of databases, you need two instances.
To change the DeploymentMode property:
  • Backup any multidimensional databases on your server and either detach them or delete them. You will not be able to load them on the tabular instance.
  • Copy the msmdsrv.ini file to your desktop. For my instance (which I called TABULAR, I installed it like that from setup),defualt location of file will be C:\Program Files\Microsoft SQL Server\MSAS11.TABULAR\OLAP\Config.
  • Open the config file in Notepad. Change the DeploymentMode property from 0 (multidimensional) to 2 (tabular), as pictured. Save and close the file.
image

  • From services.msc, restart the Analysis Services instance.



Wednesday 17 April 2013

Display Measures in Multiple Display Folders

One day, my client suggests me to create different measure group for a set of 25 measures in the cube. The main purpose was to create set of measure for different -2 users, so that they can easily search and view required measures out of hundreds. In that case, it was obvious that one measure will fall in multiple folders. Also, if folder will arrange in hierarchical view then it will more easy to find them.

This can accomplish by using display folder property of measure. Write multiple folder name separated by semicolon. If folder is hierarchical then write complete path separated by backslash. 

After reprocessing this is what the results look like below. Measure will display in those folders during browsing of the cube. This image shows a measure that lands under multiple displays folders, but this can be done with dimension attributes as well.`


Finally, it fullfill my requirement. yours?

Azure AzCopy Command in Action

Azure AzCopy Command  in Action -  Install - Module - Name Az - Scope CurrentUser - Repository PSGallery - Force # This simple PowerShell ...