Speaking the language of business intelligence with an Australian accent

Showing posts with label MonitorAnalyse. Show all posts
Showing posts with label MonitorAnalyse. Show all posts

Tuesday, March 3, 2009

Installing and Troubleshooting M&A on Win / SQL 2008

With some upcoming presentations on the horizon it was time to build a new Win 2008 VPC. I found out a few gotchas that are worth noting in order to get your fresh, standalone M&A instance up and running quickly. Please note I haven’t tried all the different install scenario permutations. I found some of the points below helped me to get things working as they should.

Pre-Install

First some pre-install tips. Don’t worry if you’re reading this after you’ve installed, just keep the following in mind for next time.

UPDATE: here is a MS knowledgebase article that detailing steps to perform SQL 2008 / PPS installs

Install SP2 before you configure M&A

I don’t know of a specific reason why you shouldn’t configure the M&A server and then load SP2, but it’s probably a good practice on a fresh install. So install M&A, but don’t run the configuration wizard yet. Next install M&A SP2 (remember, you only need to execute PSCSrv.msp, the others are for Planning). Once you’re done, run the configuration wizard.

Install SQL 2005 CU 9 Updates

You may be given a pre-req warning signal while configuring the M&A server telling you that “SQL ADOMD.NET 9.0 (SP2) is not installed”. Note that this is not a red hard-stop, just a yellow warning; you can actually go ahead without these bits if you wish. I actually ignored it on one install and didn’t find any real difference in my ability to connect to both SQL 2005 and 2008 SSAS cubes, nonetheless it’s nice to have greens all the way down the checklist when you install.

Load the following CU 9 updates for SQL 2005 (no, you don’t need to have SQL 2005 installed). You can download these here.

  • SQLNCLI
  • SQLServer2005_ADOMD
  • SQLServer2005_ASOLEDB9
  • SQLServer2005_XMO

Post Install

The following assumes you have installed and configured SQL 2008, MOSS/SharePoint and PPS M&A and are having problems getting things going.

.NET Framework 3.5 & AJAX Extensions 1.0

Once you’ve run through the M&A configuration steps and subsequently try to deploy, publish or connect to the server you may come into some trouble in the form of the (very descriptive) “Unable to connect to server” error.

UnableToConnectToServer

If you try and browse to the M&A web service (http://MyServerName:40000/WebService/PmService.asmx) you might be faced with a stack trace that looks similar to this:

Configuration Error
Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.

Parser Error Message: Could not load file or assembly 'System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.

Source Error:

Line 23:     <compilation defaultLanguage="c#" debug="false">
Line 24:       <assemblies>
Line 25:         <add assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
Line 26:       </assemblies>
Line 27:     </compilation>

Source File: C:\Program Files\Microsoft Office PerformancePoint Server\3.0\Monitoring\PPSMonitoring_1\WebService\web.config    Line: 25

Assembly Load Trace: The following information can be helpful to determine why the assembly 'System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' could not be loaded.

The .NET Framework 3.5 is a pre-req for SQL 2008. Excellent. AJAX is now a built in component of 3.5, so when we ran the M&A Configuration Manager we no longer get a warning flag asking us to install the AJAX 1.0 extension (when configuring M&A on earlier versions of the framework we were warned that we needed to install the AJAX 1.0 components). However, this appears be a red herring – it seems installing v1.0 of AJAX will actually be more of a help than a hindrance.

From my testing these problems seem to be caused by M&A still looking for version 1.0.61025.0 of AJAX but not finding it. Simply changing the value in the Version attribute in various web.config files as I referenced in this post some time ago seems to help but did not resolve the problem completely for me this time.

Solution: If your M&A server is already installed and configured don’t worry. Download and install the AJAX Extensions 1.0. After an IISRESET you should be good to go.

Ensure the Application Pools are Started

I found that when I did a fresh install on Server 2008 some of the M&A application pools sometimes did not get started automatically. This can result in “503 Service is Unavailable” and / or “Unable to connect to server” messages. Go into the IIS manager and ensure both the Preview Site and Monitoring Service application pools are started.

Friday, January 23, 2009

R.I.P. PerformancePoint Server

I just love a good premature leak, don’t you? Let’s spell it together… N-D-A.

Anyhoo the announcement has now been made officially on The BI Blog along with an explanatory video from Guy Wiesmantel. PerformancePoint Server, as a standalone product, is being retired. There are two main takeaways from this announcement:

1. Monitoring & Analytics will live on and is to be incorporated into future versions of MOSS Enterprise. So M&A is staying but will be considered a part of MOSS, to be known as “PerformancePoint Services”. I would assume this embedded version of M&A will completely replace the current (and very ordinary) BI/dashboarding capabilities that are bundled with MOSS Enterprise.

2. The Planning part of the PPS product is being retired. Naturally, it will still be supported up until its end-of-life but that will be it. Aside from a to-be-released SP3 no further PPS Planning development will happen. Budgeting & forecasting functionality as is currently provided by Planning will no longer be part of the MS BI stack.

Interesting times…

Friday, December 12, 2008

SSAS 2008 Dynamic Sets in Analytic Reports

The primary aim of PPS SP2 is really platform support, particularly the addition of SQL 2008 as a data source. One of the subtle new features of Analysis Services 2008 is the support for dynamic named sets. Now that we can connect to 2008 cubes we can take advantage of them.

In 2005 we could create named sets but the members they contained were static did not change once the cube had been processed. This is probably why the 2005 AdventureWorks cube doesn't contain any TOP / BOTTOMCOUNT named sets - they were static and not of much use. In 2005 if we want a dynamic TOP n result set we need to write an MDX statement containing a session-scoped WITH SET statement.

WITH
  SET [Top 10 Selling Products] AS
    TopCount
    (
      [Product].[Product].[Product].MEMBERS
     ,10 
     ,[Measures].[Sales Amount]
    )
SELECT
  [Measures].[Sales Amount] ON 0
,[Top 10 Selling Products] ON 1
FROM [Adventure Works]
WHERE
  [Date].[Calendar].[Calendar Year].&[2002];

If we wanted a PPS analytic report displaying TOP / BOTTOM n data from an SSAS 2005 data source we had to plug an MDX statement into the analytic report definition like the one above. Because we had to write manual MDX in order get the desired result the user lost their right-click interactivity in the deployed dashboard.

Enter SSAS 2008 dynamic named sets.  By setting a named set's Type property to Dynamic we now have a set that will recalculate its members based on the context of the query it is referenced in.

SSAS2008DynamicSet

CREATE DYNAMIC SET CurrentCube.[Top 10 Selling Products] AS
    TopCount
    (
      [Product].[Product].[Product].MEMBERS
     ,10
     ,[Measures].[Sales Amount]
    ) ;

Because the named set is an object within the cube we can now build out an analytic report using drag & drop and don't have to touch the MDX to get what we need. As a result users have full access to the right-click menu.

Demo

I set up 3 analytic grid reports using a named set called Top 10 Selling Products and embedded them in a dashboard.

  1. References a Top 10 Selling Products dynamic named set I defined in the AdventureWorksDW2008 cube
  2. Manual MDX implementation of Top 10 Selling Products completely defined in the query tab of the Analytic View Designer (using the MDX code above)
  3. References a Top 10 Selling Products named set that I defined in AdventureWorks for SSAS 2005 (a static named set)

I created a single date filter and hooked each of the grids up to it. As you can see from the shot below. At the All Periods level all three grids show the same 10 products and the same Sales Amount totals. All is well.

AllPeriods

When we filter on a year, say CY2002, we see several things.

  1. The SSAS 2008 grid is noticeably faster and completes rendering first with accurate results
  2. The manual MDX implementation results match those returned by the SSAS 2008 version, as it should, but it was slower.
  3. The members that make up the SSAS 2005 named set do not change. We get gaps for the products that we didn't sell in 2002 - like the Mountain-200... bikes. We must have sold plenty of them in later years as the static set put them at the top of the list for all time sales.

CY2002

Now, let's try interacting with our two accurate grids. As expected the Manual MDX version has no drilldown capabilities. Remember that this limited drill functionality is by design - if you change even one character of the MDX on an Analytical report user interactivity features are disabled.

ManualMDXNoDrill

Now here's the good bit. Because the SSAS 2008 grid was built using drag & drop with no hand-altered MDX we have full right-click access to the data behind it.

SSAS2008Drill

So, if you're using (or about to start using) SSAS 2008 get stuck into Dynamic Named Sets and put them to use in your cubes.

The main advantages:

  • Drag & drop analytic report design = faster, simpler development
  • Enhanced user experience in the dashboard
  • More centralized logic in the cube, less code in the element definitions
  • Faster performance

Monday, June 9, 2008

PPS M&A SP1 DataSource Cache Bug

After installing SP1 I had a demo dashboard that all of a sudden performed far slower than it did on the original RTM build. The analytic charts pointing to my OLAP cube were unbelievably sluggish; like 30 sec+ to return result sets on queries that, when executed in SSMS, ran in milliseconds. After some testing I came up with the answer. It was the Cache Setting on my data source. At some point I had set the cache interval on the data source to 0 and not changed it back to a more reasonable number.

In the RTM build of M&A a cache interval of 0 on a multidimensional data source didn't have a noticeable performance effect, you simply lost any caching benefits as the cube was always re-queried. A bug in SP1 makes queries to MD data sources with a 0 cache setting take far longer. When I contacted them the PPS team confirmed that this is indeed a bug and they're already working on a fix.

ZeroCacheSetting

The workaround: If you have already applied SP1 find any published multidimensional data sources with a cache setting of 0 and set it to something higher - anything above zero seems to work. Unless you are hitting an absolute zero-latency cube there aren't many good reasons for not taking advantage of some caching. I often find that the 0 creeps in there when testing and gets forgotten.

As far as I can ascertain tabular data sources do not seem to be affected.

An easy way to find your published data sources with a 0 cache setting? Easy! Use the MAUDFs. Once MAUDF is set up finding the offending data sources is as simple as running this query:

SELECT * 
FROM MAUDF.DataSourceMetadata()
WHERE DataSourceType = 'Multidimensional'
 
AND MinutesToCache = 0

ZeroCacheDataSources

Monday, June 2, 2008

The PPS Monitor & Analyze UDF Project (MAUDF)

I've often wanted to be able access metadata within a monitoring server with greater ease. Querying the PPSMonitoring database is difficult because the more interesting pieces of information pertaining to a particular element are locked away within the SerializedXML column of the FCObjects table. Sure we can access the data in the SerializedXML column with XPath / XQuery but I really wanted to get stuck into some CLR stuff and figured UDFs would provide the greatest reuse, flexibility and query-ability.

I've created a series of CLR table-valued UDFs and created a home for it on Codeplex, a project that I have named MAUDF (taking a bit of inspiration from the ASSP project). Using the CLR the MAUDFs connect to the PPS Monitoring web service and extract pertinent metadata and return the results in a tabular format.

Why UDFs?

The use of table-valued UDFs enables element metadata to be queried, JOINED and (CROSS | OUTER) APPLY-ed  in T-SQL in as if they were tables, opening up the world of M&A metadata to a much wider audience.

Using the UDFs

Some of the UDFs do not require a parameter value, simply executing these functions returns a tabular result set that can be used as if it were a table like the example below that calls MAUDF.ElementMetadata(). 

-- Get metadata for all elements with a display folder of "PPS Demo"
SELECT *
FROM MAUDF.ElementMetadata()
WHERE DisplayFolder = 'PPS Demo'
ORDER BY ElementType

PPSDemoElements

The remaining UDFs take a single parameter: the GUID that identifies the element in question. We can supply that value by using APPLY, all we need is an anchor table from which to reference the element IDs. In the example below we use the MAUDF.ElementMetadata() function to provide the anchor record set.

-- Get the custom property details for KPIs that have custom properties defined
SELECT 
  ElementName AS ElementName
  ,PropertyType
  ,PropertyName
  ,PropertyDescription
  ,PropertyValue
FROM MAUDF.ElementMetadata() e
 
CROSS APPLY MAUDF.ElementCustomProperties(ElementID) cp
WHERE e.ElementType = 'KPI'

I have also created a view named MAUDF.vFCObjects which is based on the data in the FCObjects table. The view definition simply adds a textual ElementType column. The same query shown above be duplicated using the MAUDF.vFCObjects view as an anchor for the CROSS APPLY operation.

SELECT 
  ElementName AS ElementName
  ,PropertyType
  ,PropertyName
  ,PropertyDescription
  ,PropertyValue
FROM MAUDF.vFCObjects f  --using vFCObjects as an anchor for CROSS APPLY
 
CROSS APPLY MAUDF.ElementCustomProperties(ElementID) cp
WHERE f.ElementType = 'KPI'

The main difference between the using an MAUDF or vFCObjets view is query performance. Because vFCObjects is based on a physical table with indexes you can immediately limit the number of rows that are made available to the CROSS APPLY thereby increasing performance. The MAUDF.ElementMetadata() function must first generate an entire result set for all published elements and then this is reduced based on the contents of the WHERE clause, which can take a bit longer.

There are different situations where one query structure will out-perform the other but not by too much. The aim of providing both is flexibility and choice.

MAUDF Schema

All UDFs and supporting objects are created within the PPSMonitoring database in their own schema, cunningly named "MAUDF".

Sample Queries

Below are some more sample queries. All these and more are contained in the Codeplex project. Some of the samples use the no-parameter-UDFs as an anchor to CROSS APPLY to, others use the vFCObjects view. The choice is yours as to which suits your requirements.

-- Which elements has "NT AUTHORITY\Authenticated Users" been granted access to?
SELECT

   f.ElementTypeName
  ,f.ElementName
  ,m.MembershipRole
FROM
MAUDF.vFCObjects f
  CROSS APPLY MAUDF.ElementMemberships(ElementID) m
WHERE
MembershipLogin = 'NT AUTHORITY\Authenticated Users'
ORDER BY f.ElementTypeName

ResultSetMembership

-- Get the count of each report type published to the server
SELECT
   ReportType
 
,COUNT(*) ReportCount
FROM MAUDF.ReportMetadata()
GROUP BY ReportType
ORDER BY COUNT(*) DESC

ResultCountReportType

-- Get all Scorecard annotations
SELECT
  f.ElementName
  ,CommentTitle
  ,CommentMessage
  ,AnnotationKpiMetricName
  ,AnnotationTuples
  ,FilterSlice
  ,AnnotationKpiID
FROM MAUDF.ScorecardMetadata() s
  CROSS APPLY MAUDF.ScorecardAnnotations(s.ScorecardID) sa
  INNER JOIN MAUDF.vFCObjects f
    ON s.ScorecardID = f.ElementID
ORDER BY s.ScorecardID, AnnotationID, CommentCreatedDate

ResultScorecardAnnotations

As a Report Source

Once you can easily access element metadata in a tabular format the creation of SSRS reports becomes far easier.

For example, a common request from many customers relates to the display of threshold banding numbers set for a particular KPI target. The SSRS report depicted below displays the threshold band numbers and the indicator icons associated with them each target in a KPI. The report takes a KpiID as a parameter. The report can then easily be incorporated into a dashboard by creating a filter link from a scorecard to the report passing the KpiID.

SampleSSRSReport

The SQL code to return the result set for this report is also contained in the samples.

Where do I get it?

The MAUDF setup instructions, source code, release binaries, samples, documentation and more can be accessed from the MAUDF Codeplex project.

I'm looking forward to hearing feedback and any new ideas anyone may have. Please note that this is the first time I have written anything seriously in C# (or any other .NET language for that matter).

Thanks very much to Darren Gosbell for his early alpha testing and feedback.

Thursday, February 28, 2008

Creating Dynamic Web Page Reports

As a follow up to my post on debugging filter links with web page reports I thought it would be worthwhile to put together a quick example to illustrate just what an unsung hero the web page report type is. Just think of the web page report as the catch-all report type. Basically, if you can't do it with one of the many pre-baked M&A report types then the web page report is what you want.

In the debugging filter links post we saw how dashboard items communicate with each other by embedding data in the Request.Params collection. In that example we simply displayed the contents of this collection. The next logical step is to actually do something with those contextual values we are passing to the report item at runtime. Remember that all the web page report does is send the user to a static URL, the dynamic part comes from two places:

  1. the incoming filter links configured on the report item embedded in the dashboard
  2. what is done with this filter link data by the code contained in the page we send the user to

Web page reports pretty much opens up the entire .NET framework to us, the possibilities are virtually limitless.

For example, let's imagine (in a somewhat bizarre set of circumstances) that our users want a dashboard page that will allow them to select a which search engine they wish to use. They wish to select their search engine of choice using a dropdown. the home page of the search engine name they select will appear in the dashboard and they can then search to their hearts content.

1. Create a tabular data source for the search engine filter

This will be done using a simple Import from Excel 2007 Workbook tabular data source and manually entering the names of three lesser-known search engines. Please note that they are arranged in alphabetical order, nothing more :)

TabularDataSource

Note the Column Name property in the shot above is set to SiteName. This value could be anything but be aware that when creating filter links from a tabular data source filter it is this column name value that will be used as the name of the item that is added to Request.Params.

2. Create the redirect ASPX Page

Next is to write the code for our redirect page. This will be the page that we point the web page report towards and contains the logic that makes our report dynamic.

In this example I have called it SearchEndineRedirect.aspx. Once completed drop the file (or a copy of it) into the %Program Files\Microsoft Office PerformancePoint Server\3.0\Monitoring\PPSMonitoring_1\Root\ directory.

Here is the code for that page.

<%@ Page Language="C#"%>

<%
    if(!string.IsNullOrEmpty(Request.Params["SiteName"]))
    {
        string SearchEngine = Request.Params["SiteName"];
        string WebSite = "
http://www." + SearchEngine + ".com";
        Response.Redirect(WebSite);
    }
    {
        Response.Write("No filter values available yet - create a dashboard and configure a SiteName filter link on this report");
    }
%>

All this code is does is look for the item named SiteName in the Request.Params collection and then concatenates the value contained therein with a "http://www." in front and a ".com" at the end. We then redirect the user to this newly-generated URL.

3. Create a web page report

Configure the URL property to point towards the newly-created SearchEngineRedirect.aspx page (http://localhost:40000/SearchEngineRedirect.aspx) as seen below.

WebPageURL

Remember, all we're doing is sending the user to a URL, it could be any URL. Preferably, though, we want it to be a page that has been created with the intention of doing something useful with the filter link values that are going to be passed to it. Remember, we can also pass static parameter values to our report via the web page report URL. This technique is detailed in the debugging filter links post

Note that our C# code from step 2 checks whether the SiteName item of Request.Params collection IsNullOrEmpty. In essence we're checking whether this item exists in the collection and handle things from there. By doing this we avoid a stack trace error being displayed in the DD interface when configuring the report because, at this point, the SiteName item can't exist; we need to create the filter link in the dashboard first. Handling this unavoidable situation elegantly helps in confirming that our ASPX page is ready for use.

4. Create and publish the dashboard

Create a simple 1 page dashboard and create a Tabular Values filter referencing the Search Engines data source and using the SiteName field configured in step 1.

DashboardUIFilterLink 

5. Deploy the dashboard to the preview site and test

Now all that is left is to admire our handiwork. As you can see from the shots below the user's interaction with the dropdown passes the selected value to our SearchEngineRedirect.aspx which then generates the URL and redirects them to the appropriate page via the web page report.

DashboardGoogle

DashboardLive 

The sample workspace and .aspx file used in this post can be downloaded here.

Sunday, February 24, 2008

Debugging Filter Links with Web Page Reports

Often when hooking up and testing dashboard filter links you may find the need to see precisely what value is being passed by that filter link. This becomes particularly urgent if you just can't figure out why things in your dashboard are not functioning the way you expect them to.

A few months ago the PPS team put out this post about using web page reports to mimic the absent OverridingURL functionality that used to exist in BSM. It is this technique that I have adapted to create a simple debug page to display the values a filter link passes across to other dashboard items.

Dashboard Filter Links and Request.Params

For those who may not have done much web development (this includes me) the Request.Params collection typically contains things like browser metadata, cookies, server variables and query string values among others. It is a common means of providing page-to-page communication within web applications.

Filters and scorecards pass outgoing filter link data to other dashboard items by appending the data to the Request.Params collection. The receiving dashboard item finds the appropriate Request.Params item it has been configured to look for in the collection and obtains the data needed to drive its behaviour.

What we want to do is simply expose the items in the Request.Params being sent out by either a dashboard filter or scorecard item so that we can see what they're passing across.

1. Create & Configure ASPX page

Create an .ASPX file named RequestParamItems.aspx using the following code. (thanks to Hassan Syed for his help filling the gaps in my C# skills)

<%@ Page Language="C#"%>

<%
    for (int i = 0; i < Request.Params.Count; i++)
    {
        Response.Write(
            "<b>Param Name: </b>" + Request.Params.AllKeys.GetValue(i) + "<br>" +
            "<b>Param Value: </b>" + Request.Params[i].ToString() + "<br><br>");
    }
%>

The code contained in the file is simple and can certainly be expanded to do much more. All this version does is iterate through the page's Request.Params collection and write the values out. Once complete copy the file into the %Program Files\Microsoft Office PerformancePoint Server\3.0\Monitoring\PPSMonitoring_1\Root\ directory.

2. Create Web Page Report

Using Dashboard Designer create a web page report that references this file that has been dropped in the Root directory. Note the URL property in the shot below points towards http://localhost:40000/RequestParamItems.aspx.


FilterLinkValuesDebugReport

Once set up, the report immediately retrieves the static members of the Request.Params collection. This provides a good way to confirm that your report is configured correctly and is ready to do its job once contained in a dashboard.

There's some interesting data that is brought back at this initial stage but where are the custom filter link values? They don't exist yet, we have to create them in a dashboard first. The web page report itself when viewed in DD will never contain anything more than the default members of the Request.Params collection.

3. Use the web page report to a dashboard

Add the web page report to a dashboard and create incoming filter links on it. A new item is added to the top of the Request.Params collection for each unique filter link source value name (e.g. Display Value, Member UniqueName etc.) that is added to the report. The filter link values associated with each source value name will be contained within the same Request.Params item delimited with semi-colons.

In the shot below I have created 6 incoming filter links on my FilterLink Values Debug report. Unfortunately from a UI perspective the links look like they are duplicated, they are not; the names of the item the filter link originates from is displayed which can be a little confusing. In fact I have added 3 Display Value links and 3 Member UniqueName links one from each of the three filters located above the report.

DashboardFilterLinks

4. Publish the dashboard and deploy it to the Preview site

Once deployed we can interact with our filters and actually see what those values are via the report. In the screenshot below you can see where the values for the filter selections for Product Color, Geography and Calendar appearing at the top of the report grouped with their source value name.

PreviewRequestParamDebug

This debugging functionality should only be used when deploying to the Preview site. It goes without saying (but I'll say it anyway) that the detailed contents of Request.Params will only be confusing to end users.

The real value of having a debug web page report like this published to the Monitoring server is reusability. Whenever you need to troubleshoot filter link values you simply add it to a dashboard and hook up the troublesome filter links.

Debug Filter Link Formulas

Note that our debug web page report can also be useful for displaying the values returned by filter link formulas. The following shot shows the resultant set that is added to the Request.Params collection after the filter link formula has been applied to the Calendar filter link. In this case it is the .CHILDREN of the currently selected filter value - the two semesters of calendar year 2004.

PreviewFilterLinkFormulaDebug

Add hard-coded parameters

It should also be noted that we can manually add values to the Request.Params collection via the URL configured in the report definition. Simply add a "?" followed by the name you want to give parameter and the value to be assigned to it separated by "=".

WebPageReportCustomParameter

While the addition of a hard-coded parameter is definitely not a dynamic solution at all it can still be very useful in certain situations. For example, the project I am currently working on requires users be able to write and save textual commentary at the dashboard page level. The .NET team has developed a great comment collector control which they embedded in an ASPX page.  We call this page using a web page report and hook up the appropriate filter links in the dashboard. However, each instance of the control needs to "know" what dashboard page it is located on so that the comments entered can be properly associated to that particular page. To solve this we've created an instance of the comment collector web page report for each dashboard page, we simply append an extra parameter to each report URL which passes the name of the page that the comment collector will reside on. 

Remember that the URL in a web page report is static, we cannot alter it at runtime. All we can do is tell the web page report where it needs to send the user. What happens after that is up to the code within the page in concert with the contextual data provided by filter links and/or URL-based static parameters.

The sample workspace file and .aspx page used in the shots above can be downloaded here.

Friday, February 22, 2008

PPS Web Service Connection Issues & .NET 3.5

Recently I came across another connection problem that was not related to data sources or application pool account privileges. We were unable to connect to the web service in Dashboard Designer but couldn't figure out why not. We checked everything. Eventually we tried to simply browse to the web service location in IE. On trying to browse the .asmx we were faced with a descriptive stack trace that gave us more more of an idea of where to look to solve the problem. BTW, it is worth noting that we were working on a standalone PC being using for development, not a server.

The solution came courtesy of Hassan Syed, an excellent .NET consultant I have been working with recently who maintains a blog named "From fragile to agile" (love the name). Without stealing too much of his thunder I will say that the problem was probably related to installing .NET 3.5 long after PPS M&A had been configured and had been working without issue. Hassan has documented what was done to bring the web service back on line here.

It should come as no surprise that a newer version of the framework could possibly cause problems with software that was written on an earlier version. Nonetheless, if you do want to upgrade to 3.5 Hassan's post is worth noting.

Wednesday, February 6, 2008

Show Details functionality on Scorecards

A somewhat unknown feature of scorecards is the ability to right-click a cell and drill to the details behind it by selecting Show Details. By default, however, the show details right-click option always seems to be grayed out. Why?

ShowDetailsRightClickDisabled

A common assumption is that this is a scorecard scoped setting like the ability to add scorecard comments. In fact, the answer to enabling this functionality lies in the calculation settings of the individual metrics of each KPI contained in the scorecard. In order to enable show details functionality the metric calculation must be set to Source data. The PPS team posted about this a while back. They also wrote a more detailed post a short time ago too that also covers drillthrough actions on analytic charts and grids, definitely worth a read.

KpiMetricCalculationSourceData

Once Source data has been selected the Show Details option will be enabled in any scorecard that contains the metric's parent KPI. Such a fine level of control can be handy for only allowing drillthrough on specific KPI metrics only.

ShowDetailsRightClickEnabled

So, the trick to getting the Show Details option ungrayed for a specific scorecard cell is to ensure the KPI metric calculation property is set to source data. However, although the item is now un-grayed... will it work straight away? Depending on the structure of your scorecard you may find that you get the following error:

Cannot show details for this cell because both the row and column must have a selection.

This basically means that the scorecard wants at least one dimension member on its row or column axis so that it has some form of reference from which to perform the drillthrough. Sometimes, though, you may not want your scorecard to have dimension members on present columns or rows; you just want straight KPIs and metrics: a "traditional" scorecard.

Here's the trick to making this work while keeping your scorecard structure the way you want it:

I found that I only needed to have one dimension reference on one axis to get things to work. All you need to do is add a benign dimension member (one that is not vital for the operation of the scorecard) on the top level of the row axis. Once added right-click the item and select Hide. In the screenshot below I added the All member of the Customer attribute hierarchy.

HideDummyAllMember

Once the dimension is hidden the dummy All Customers member that we have hidden will display in red. The scorecard has its dimension reference and end users will be none the wiser.

HiddenDummyAllMember

Now that this is done the Show Details gets its dimension reference on one axis (which seems to be enough in this case) and the drillthrough function will return a nice data set to you from a simple right-click and selection of Show details in the scorecard.

ShowDetailsWindow 

Other tips

Don't forget to ensure that the Application Pool account (or the users themselves if you've implemented PerUser security) has read access to the relational database itself and that drillthrough access has been granted on the source cube.

CubeDrillthroughAccess

Also remember that you won't have much luck performing a drillthrough on a calculated member or a metric that uses a custom MDX formula.

Tuesday, January 29, 2008

Downloadable PPS TechNet Guides

Via Aseem Nayar's posts in the PPS M&A and Planning TechNet Forums:

You can now download the following PerformancePoint Server 2007 guides as Word documents from TechNet.

Saturday, January 19, 2008

PPS Data Connection Security with CustomData

There are two well-documented data source security methods available in PerfornancePoint Monitoring & Analyzing: the default Application Security model and Per User Connections. However, as a wise green creature once whispered, "No. There is another..."

More often than not security requirements for a BI solution are based around certain users only being able to access specific members of several important dimensions. CustomData security functionality in PPS serves this purpose very well and provides a solution that sits between the two already well-known data security methods.

Application Security - a single application pool account is used to make all connections to data sources.

  • Advantage: because one account makes the data source connections the monitoring server caches results providing greater speed responsiveness to all users.
  • Disadvantage: no data security is possible based on who the user is because all users are connecting via one the account; the database does not know who they are.

For more details on the common connection pitfalls of application security please see this post.

Per User Connections - each user's credentials are used to connect to data sources.

  • Advantage: highly secure, naturally this security is dependant on there being some sort of existing security framework within the data source itself.
  • Disadvantage: little or no caching of dashboard data can occur as each data request is made with the individual user's credentials. Dashboard responsiveness and speed can take a hit.

Security is important to all the clients I work with but I always advocate careful thought and consideration before simply switching on Per User connections on a PPS Monitoring server. There is definite performance hit that comes from the fact that each user gets his or her own data. For more information on the performance difference between the two principal security methods please see the PPS Performance Tuning and Capacity Planning whitepaper.

At the time of this writing, not much official documentation exists on CustomData security, hence the reason for this post. The only reason I knew of its existence originally was this post on the PPS team site some time ago. In that post lip service is paid to the CustomData option but we're really told much more than "it's possible".

What is CustomData Security?

CustomData security is a middle ground between application and per user security. We still use an application pool account to connect to the data source, but we also have access to data about the Domain\Username of each user who is interacting with the deployed dashboard. We use this user-specific data to drive security dynamically using information configured in the relational database the cube sources data from. This alleviates having to configure and maintain many SSAS database roles tied to specific domain accounts or groups. Instead we configure a single, dynamic MDX based role which will be detailed later.

NB: there is no discernable data caching advantage to using CustomData Security. The performance is much the same as when using the PerUserSecurity model. If performance is the most important factor in a PPS deployment then Application Security is certainly the best performing option.

What is Dynamic Dimension Security?

Limiting user access to certain members of a particular dimension attribute hierarchy based on their windows credentials is nothing new. For example, dynamic dimension security may decree that when I look at a dashboard I can only see Australian states in the State/Province dashboard filter.

FilterAustralia

...while on the other hand Adrian should only see a list of Canadian provinces.

FilterCanada

The majority of work to set up CustomData security involves the creation of a dynamic dimension security framework in your multidimensional data source and the relational source that feeds it, not PPS. If you already have security of this kind set up on your UDM then you're already most of the way there. The set up is minimal on the PPS side of things.

How I set up SSAS dynamic dimension security?

Providing any user-driven security access to PPS data cannot function without some form of back-end, SSAS and relational security infrastructure. There's a little bit to do to set this up, so instead of going into a long-winded walk-through I will instead point to two excellent articles/posts on the topic. Both of these documents cover similar ground. Using a dimension containing user details and a factless fact table to relate each user to the specific members of the dimension they are allowed to see e.g. Reseller Stores. Once the relational database infrastructure and data is in place, a SSAS role is set up containing MDX code to return a set of the allowed dimension members for the current user. I highly recommend reading at least one, if not both in order to full understand the remainder of this post.

  • Brian C Smith of Hitachi Consulting wrote this blog post that contains sample T-SQL code and steps to set up a simple UDM.
  • Teo Lachev wrote this article for SQLMAG in which he covers a number of different techniques including the factless fact approach.

These are just two examples of how to implement dynamic dimension security. I'm sure there are many other creative ways to implement this kind of functionality.

How do I turn on CustomData security?

As mentioned earlier, the PPS configuration is minimal. Bpm.UseASCustomData is a boolean attribute that can be found in the same web.config files as the Bpm.ServerPerUserConnection attribute. Change the BPM.UseASCustomData attribute from False to True in the appropriate web.config files as listed below.

  • Preview Site: %\Program Files\Microsoft Office PerformancePointServer\3.0\Monitoring\PPSMonitoring_1\Preview\
  • Web Service: %\Program Files\Microsoft Office PerformancePoint Server\3.0\Monitoring\PPSMonitoring_1\WebService\
  • SharePoint: %\Inetpub\wwwroot\wss\VirtualDirectories\80\

WebConfigAttributes

NB It is very important to remember that the Bpm.ServerPerUserConnection be set to False when using CustomData security. We want to connect to the data source using the Application Pool account, not each individual user. Turning on Per User connections completely defeats the purpose of the security method being discussed here.

What does UseASCustomData do?

When Bpm.UseASCustomData is switched to True any PPS data source connections made to Analysis Services 2005 contain an extra attribute on the connection string: <CustomData>. The CustomData connection string attribute was added to SSAS 2005. The Monitoring server will populate this attribute with the Domain\Username of the user making the request. The data source connection itself is still being made as the application pool account.

This can be particularly useful in multi-server environment where Kerberos is not configured and the double-hop issue is encountered. The information in the CustomData field can now be used to identify the user without the need for Kerberos.

How do I confirm that CustomData is switched on?

Once you have made the adjustments to the appropriate web.config files, set up a SQL Profiler trace on the SSAS server where your cube is located. Use Dashboard Designer and run a Test Connection on one of your SSAS data sources.

As you can see from the shot below the connection to the cube is being made by my Application Pool account, NETWORK SERVICE (in a production environment you would want to be using a specific domain account for the app pool identity). More importantly note that there is a <CustomData></CustomData> attribute that has been added to the connection meta data containing my Domain\Username details.

ProfilerCustomDataAttribute

How do I make use of the CustomData attribute?

In order to get at the Domain\Username string that PPS provides within CustomData we use the CUSTOMDATA() MDX function. The CustomData connection string attribute does nothing more than hold a string of characters. The CUSTOMDATA() MDX function simply returns that character string to us, we can do whatever we want with it from there. There isn't a great deal of information out there about this function but Chris Webb posted about it a while back. In that post he pondered what this function could come in handy for. Hey Chris, I think this is a good one.

In MDX you can gain access to a string containing the Domain\Username of the currently connected user by via the USERNAME MDX function. USERNAME is the MDX equivalent of the T-SQL SUSER_NAME() function. Try running this query in SSMS to return your Domain\Username.

WITH MEMBER [Measures].[MyUsername] AS USERNAME
SELECT
[Measures].[MyUsername] ON 0
FROM [Adventure Works]

The USERNAME function is used in the articles listed above to access the Domain\Username string for the connected user to drive the dimensional security. The functionality detailed by Teo and Brian is relevant when a user connects to the cube "as themselves" i.e. they are accessing the cube with their individual Windows credentials via Excel, SSMS, ProClarity or even PPS with Per User security. Because of this SSAS knows who each user is.

With PPS CustomData security our aim is a little different: we want to avoid connecting to the cube with individual user credentials. Under the application security model the connection is always being made by the same application pool account. In this case the USERNAME function is useless to us. It will always return the same value: that of the application pool identity account (in my example trace above it would return NT AUTHORITY\NETWORK SERVICE every time). When UseASCustomData is switched on, the Monitoring Server sneakily adds the Domain\Username string to the CustomData attribute for each individual user who interacts with a dashboard. Now, if we don't do anything else the string in the CustomData attribute will simply sit there benignly minding its own business.

Here's the trick: using the same techniques detailed by Teo and Brian we replace the USERNAME MDX function with CUSTOMDATA(). This way we are able to access the Domain\Username value in the CustomData connection string attribute to implement the same dynamic functionality without connections being made on a per user basis.

Testing CUSTOMDATA() within Dashboard Designer

Here's another way of testing that CustomData security is configured on the Monitoring server. Within Dashboard Designer create an analytic grid report and enter the following MDX in the Query pane.

WITH MEMBER [Measures].[MyUsername] as CUSTOMDATA()
SELECT
{ [Measures].[MyUsername] } ON 0,
NON EMPTY { [Geography].[Geography].[All Geographies] } ON 1 
FROM [Adventure Works]

Switch to the Design pane to check that your own Domain\Username is returned.

AnalyticGridResult

Typically you will not use CUSTOMDATA() in an MDX statement within Dashboard Designer. It is best to keep the MDX code that drives the security within the roles managed by SSAS as described in the referenced articles.

How do I set up dynamic dashboard filters?

Once the Bpm.UseASCustomData attribute is set to True and your back-end SSAS security framework is set up the creation of dynamic filters could not be easier. The heavy lifting is being done by the SSAS roles. The easiest filter to create is an MDX Query filter type. All that is needed to populate the example State/Province filter that limits Adrian and my access to the states/provinces of our respective countries of birth is the following, very simple, MDX.

StateProvinceFilter

Note that I do not need to reference the CUSTOMDATA() MDX function here. All that logic should be contained in the SSAS role that defines the security behaviour.

A word on roles

If you have gone to the trouble of setting up a user-driven security infrastructure in your SSAS cube the last thing you want to do is limit the security access to just PerformancePoint monitoring. All other cube browsing applications should be able to take advantage of what has been created. The simple way is to create at least two roles: one (or more) for all users to connect with user/role based Windows security for Excel, ProClarity, SSMS etc.etc. and a second role for PPS data source connections.

The Windows based role/s grants access to whichever domain groups and users require it. This is the general windows security access role for non-PPS connections. Users are recognised by their windows credentials and the MDX USERNAME function is referenced to apply security in the dimension security MDX statements.

The PPS role need only provide access to the domain account used by the PPS application pool identity. This role uses the CUSTOMDATA() function in the dimension security MDX statements instead of USERNAME. The role name is then referenced in the PPS data source definition as seen below so that we can be sure the connection to SSAS is made using the permissions defined therein.

DataSourceRole 

A role security MDX tip

I have learned from reading Mosha's blog that you should try to avoid using STRTOMEMBER or STRTOSET functions if possible for performance reasons. The sample code in the dimension security articles use these functions in the dimension security MDX. I have provided some sample MDX code that alleviates the need for the STRTO... functions. Note that the sample code contains references to both CUSTOMDATA and USERNAME functions, you can only use one at a time.

For example, instead of

EXISTS(
[Reseller].[Reseller Name].MEMBERS,
STRTOMEMBER("[Employee].[Login ID].&[" + CUSTOMDATA() | USERNAME + "]")
,"Security Filter"
)

Try using this

EXISTS(
[Reseller].[Reseller Name].MEMBERS,
FILTER(
  [Employee].[Employee].[Employee].MEMBERS,
  [Employee].[Employee].CURRENTMEMBER.PROPERTIES("Login ID") = CUSTOMDATA() | USERNAME
 
)
 
,"Security Filter"
)

UPDATE: 29th Feb 2008. David Gustavson, author of the Performance Tuning and Capacity Planning for PerformancePoint Monitoring Server whitepaper has informed me that there is virtually no caching benefit when using the CustomData data connection method described here. The original version of this post indicated that CustomData provides similar caching performance to Application Security - this is incorrect. In fact the cache performance is not much better than using Per User Connections. I have altered the post to reflect this.

Friday, January 18, 2008

Rational Guide to PerformancePoint Planning Now Available

The Rational Press just have let us know that The Rational Guide to Planning with Microsoft Office PerformancePoint Server 2007 is now available. Adrian has a full chapter breakdown and more here. If you've got to get your hands on a copy of the book immediately you should order it directly from Rational Press. You will find that Amazon and other booksellers will not list the book as available for a few days yet.

Rational_PPS_Planning

It's been around 18 months since Adrian rang me and suggested that we write a book on BSM together. Here we are with our third Rational Guide completed, who-da thunk it. Thanks are due to all who helped us achieve this significant milestone. Tony Mann, Jeff Edman and the team at Rational Press; our tech editors Ian Tien, Corey Hulen and Peter Bull. Thanks also to Bruno Aziza and Bill Baker for their support and work behind the scenes.

A very special thank you goes to our respective wives and daughters, Mary, Christine, Angela and Olivia for putting up with those late night, early morning and weekend absences; we couldn't have done it without them.

...and of course, thanks to co-author, colleague and friend Adrian Downes, to whom I remember saying "you want a book on BSM together, are your crazy?!"

Wednesday, January 16, 2008

Time Intelligence Filter Display Caption Tip

If you don't provide a caption for an item when creating your Time Intelligence filter the TI engine will simply populate the name of the member that the STPS formula relates to.

For example creating a TI filter as seen below with no caption values...

TIFilterDialogNoCaptions

... will result in a filter populated like this

TIFilterNoCaptions 

The only caveat to the "no caption" approach is if you've stipulated a STPS formula that returns a range of members e.g. Month-7:Month-1. In these cases you should provide a caption otherwise the formula itself will appear in the filter. As you can see in the shot above, the items that get a non-geek-readable name are the range formulas that return more than one member.

On the other hand, if you provide captions...

TIFilterDialogWithCaptions

The captions will be displayed accordingly...

TIFilterCaptions

The use of STPS formula captions is not an all or nothing deal. Mix and match with or without captions as required.

TIFilterCaptionsMixture

For more Time Intelligence / STPS reading have a look a David Francis' excellent post on the topic.