Using SSIS to Automate the Creation of Cube Partitions

Who is online?  0 guests and 0 members
Home  »  Articles  »  Using SSIS to Automate the Creation of Cube Partitions

Using SSIS to Automate the Creation of Cube Partitions

change text size: A A A
Published: 2/2/2010 by  DevinKnight  - Views:  [2362]  

Partitions are a feature in Analysis Services to help optimize cube performance.  In a previous article I explained why partitions are so helpful and how you can create them to be used in your cube.  For the purposes of this article though most of the demonstration will be done in Integration Services.

Many companies find the need to create partitions on a monthly, weekly, or even daily basis depending on how large their fact table loads are.  With some companies having billions of new records loaded into a fact table daily it creates an obvious need for multiple partitions.  Having a DBA or Developer manually create these partitions can be time consuming and means you have to rely on a human being to remember to create the partition daily.  A great alternative is to have Integration Services do all the work for you.  You can create an SSIS package to handle the partition creation, use the SSIS expression language to dynamically change the partition name and storage date range and then finally you can schedule it to run the appropriate number of times.  It just seems natural to take another great BI tool that already has a task that can handle the work to automate a tedious job. 

In this example I will make the assumption that your company needs partitions to be created on a daily basis.  If it needs to be less frequent then adjust accordingly.  This example will also assume that you have created partitions previously so if you haven’t follow the link at the top of this article to learn how to create partitions from BIDS (Business Intelligence Development Studio).

Example

1.       Connect to the Analysis Server through Management Studio to script out the XMLA used to create a partition. 

2.       Expand the Analysis Services database you wish to partition.  Next, select the appropriate cube and finally measure group.  Expand the partitions folder then right-click on one of the available partitions and select Script Partition as -> CREATE To -> New Query Editor Window (These partitions were created in the previous article linked above if you wish to follow the same example)

 

3.       When the XMLA creation script is created do a find and replace so all double quotes (“) are replaced with \”.  This will help in preparing the script to be used in the SSIS expression language.  Read this blog post to better understand why the \” is needed.  Leave this query here for now, you will come back to it.

4.       Create a new SSIS package and bring an Analysis Services Execute DDL Task into the Control Flow of the package. 

5.       Add two variables to the package one called strCurrentDate and one called strXmlaStatement both with String data type.

 

6.       The strCurrentDate variable should have EvaluateAsExpression set to True and the expression should read:

REPLACE( ( DT_WSTR, 10) (DT_DBDATE) GETDATE(), "-", "" )

Which returns the current date as a string without hyphens like this:

20100202

7.       The strXmlaStatement variable should also have EvaluateAsExpression set to True but the expression should use the XMLA query that you have in Management Studio.  This expression should look like this (with the changes highlighted):

  

"<Create xmlns=\"http://schemas.microsoft.com/analysisservices/2003/engine\">

    <ParentObject>

        <DatabaseID>PASS</DatabaseID>

        <CubeID>Adventure Works</CubeID>

        <MeasureGroupID>Fact Internet Sales 1</MeasureGroupID>

    </ParentObject>

    <ObjectDefinition>

        <Partition xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:ddl2=\"http://schemas.microsoft.com/analysisservices/2003/engine/2\" xmlns:ddl2_2=\"http://schemas.microsoft.com/analysisservices/2003/engine/2/2\" xmlns:ddl100_100=\"http://schemas.microsoft.com/analysisservices/2008/engine/100/100\">

            <ID>Internet Sales " +@[User::strCurrentDate]+ " </ID>

            <Name>Internet Sales " +@[User::strCurrentDate]+ "</Name>

            <Source xsi:type=\"QueryBinding\">

                <DataSourceID>Adventure Works DW</DataSourceID>

                <QueryDefinition>SELECT [dbo].[FactInternetSales].[ProductKey],[dbo].[FactInternetSales].[OrderDateKey],[dbo].[FactInternetSales].[DueDateKey],[dbo].[FactInternetSales].[ShipDateKey],[dbo].[FactInternetSales].[CustomerKey],[dbo].[FactInternetSales].[PromotionKey],[dbo].[FactInternetSales].[CurrencyKey],[dbo].[FactInternetSales].[SalesTerritoryKey],[dbo].[FactInternetSales].[SalesOrderNumber],[dbo].[FactInternetSales].[SalesOrderLineNumber],[dbo].[FactInternetSales].[RevisionNumber],[dbo].[FactInternetSales].[OrderQuantity],[dbo].[FactInternetSales].[UnitPrice],[dbo].[FactInternetSales].[ExtendedAmount],[dbo].[FactInternetSales].[UnitPriceDiscountPct],[dbo].[FactInternetSales].[DiscountAmount],[dbo].[FactInternetSales].[ProductStandardCost],[dbo].[FactInternetSales].[TotalProductCost],[dbo].[FactInternetSales].[SalesAmount],[dbo].[FactInternetSales].[TaxAmt],[dbo].[FactInternetSales].[Freight],[dbo].[FactInternetSales].[CarrierTrackingNumber],[dbo].[FactInternetSales].[CustomerPONumber],CONVERT ( CHAR ( 10 ), SalesOrderNumber )  + 'Line '  +

CONVERT ( CHAR ( 4 ), SalesOrderLineNumber ) AS [SalesOrderDesc]

                                FROM [dbo].[FactInternetSales]

                                WHERE OrderDateKey = "+  @[User::strCurrentDate] +"</QueryDefinition>

            </Source>

            <StorageMode>Molap</StorageMode>

            <ProcessingMode>Regular</ProcessingMode>

            <ProactiveCaching>

                <SilenceInterval>-PT1S</SilenceInterval>

                <Latency>-PT1S</Latency>

                <SilenceOverrideInterval>-PT1S</SilenceOverrideInterval>

                <ForceRebuildInterval>-PT1S</ForceRebuildInterval>

                <Source xsi:type=\"ProactiveCachingInheritedBinding\" />

            </ProactiveCaching>

            <EstimatedRows>1303980</EstimatedRows>

            <AggregationDesignID>InternetSaleAgg</AggregationDesignID>

        </Partition>

    </ObjectDefinition>

</Create>"

 

The double quotes surrounding the whole XMLA statement will pass in the value as a string literal.  The ID and Name section that is highlighted will change the name of the partition that is created to include the date as part of the name.  Lastly, the Where clause section that is highlighted will change what data is stored in the created partition.

8.       Next open the editor for the Analysis Services Execute DDL Task and establish a connection to the desired Analysis Server on the DDL page.

9.       On the Expression page create a new expression on the Source property and use the strXmlaStatement variable for the expression.  Hit OK twice to confirm the expression and then the Task editor.

 

10.   Run the package and when the package lights up green you should have successfully created a new partition with a dynamic name and query using SSIS.

11.   Verify the new partition exists in Management Studio.

 

 

 

12.       Last create a SQL Agent job to run this SSIS package and schedule it to run daily.

 
0
/5
Avg: 0/5: (0 votes)

Comments (14)

PSB1
PSB1 said:
I'm interested in how you'd manage partitions depending on how you choose to process a given cube. We currently do a Process Incremental on a single partition cube via an SSIS package each night. To be honest, we only have one cube that breaks your 2Gb/50 million row guideline, so partitioning is not something that I'd automatically look at given the development and maintainance overhead there seems to be. I've implemented usage based optimisation in preference as it was much easier to put into practice and gave the users the performance they were after. However, if I rebuilt the cube with multiple partitions for, say, each month I'd either have to update the package every month to look at the newest partition, write something to change the partition definition to move the data from a "current" partition to an "archive" one or move to a full process model. Any suggestions? Cheers
2/15/2010
 · 
 
by
egan
egan said:
What's your take on partitioning the SQL tables that are used to create Views that in turn, are used by the AS DSV? We currently need to partition our AS solution about every 11 days. I read that the paritioning of your actual SQL tables is helpful but doesn't necessary need to be partitioned in the same manner. Interested in your opinion. Thanks.
2/15/2010
 · 
 
by
devinknight
devinknight said:
You could build that logic into the SSIS package. So if you wanted to create a new partition monthly build the date range logic in a variable using expressions so it's always the correct month. Usage based optimization is one of my favorite options in Analysis Services. I'm glad to hear you're using it.
2/16/2010
 · 
 
by
devinknight
devinknight said:
That's a great question Egan. I'll have to test that one myself. It makes sense logically, but I would be interested to see actually how beneficial it is to also partition your SQL tables used in the DSV.
2/16/2010
 · 
 
by
brjan
brjan said:
Thanks for you time and effort on this article. I am able to dynamiclly create the partition but have two issues. 1. The new partition does not show up in SSAS under the partitions tab, thoughts is this normal? 2. After creation of the Partition it sill needs to be processed do you have xmla code to force a full processing of the new partition. Bryan
3/20/2010
 · 
 
by
DevinKnight
DevinKnight said:
It does not show under the partition tab in you SSAS project because it was sent directly to the server. If you imported the project from the server you would see it. So right now if you redeployed your AS project it would override the partition. If you right click on the partition in Management Studio and select process there will be an option in the top left of the dialog box to script out the process.
3/21/2010
 · 
 
by
Anil
Anil said:

Hello Devin,

It's one of the nice blog post and I had also try it out by following above process but I am having certain problem after step no 8 in Analysis Services Execute DDL Task after connection set up there is also another few settings in DTL Tab so what should we set in there 

1.SourceType : what to choose either Variable or Direct Input also in

2.Source : ?

Then I followed step no 9 and there is certain error shows as

 

"Error at Analysis Services Execute DDL Task [Analysis Services Execute DDL Task]: DDL is not valid.

Error at Analysis Services Execute DDL Task: There were errors during task validation.

 (Microsoft.DataTransformationServices.VsIntegration)"

I try to implement Dynamic partition by following this blog post and other references but having some problems .

Hope you will respond soon.

Thanks,

Anil Maharjan

2/1/2011
 · 
 
by
DevinKnight
DevinKnight said:

The source type should be direct input for this example, which is the default.  This could optionally be done with variables too.  Your error looks like there's something wrong with the XMLA you're using,  but it's not descriptive enough to tell what the problem is inside the script.

2/3/2011
 · 
 
by
prashantm
prashantm said:

Hi Devin,

Scope value is not editable .  How did you describe scope as a "CreatePartitions" ?

Regards,

Prashant Mhaske

2/18/2011
 · 
 
by
DevinKnight
DevinKnight said:

CreatePartitions is just the name of the SSIS package.  So the scope is the entire package.

2/19/2011
 · 
 
by
prashantm
prashantm said:

Hi Devin ,

 

I am also facing same issue like Anil . Could you please help me  ?

here is my code

"<Create xmlns=\"http://schemas.microsoft.com/analysisservices/2003/engine\"><ParentObject><DatabaseID>AW_SSAS</DatabaseID><CubeID>Dsv Adventure Works</CubeID><MeasureGroupID>Sales Order Header</MeasureGroupID></ParentObject><ObjectDefinition><Partition xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><ID>SalesOrderHeader-2003</ID><Name>SalesOrderHeader-2003</Name><Annotations><Annotation><Name>AggregationPercent</Name><Value>25</Value></Annotation></Annotations><Source xsi:type=\"QueryBinding\"><DataSourceID>dsAdventureWorks</DataSourceID><QueryDefinition>SELECT [Sales].[SalesOrderHeader].[SalesOrderID],[Sales].[SalesOrderHeader].[RevisionNumber],[Sales].[SalesOrderHeader].[OrderDate],[Sales].[SalesOrderHeader].[DueDate],[Sales].[SalesOrderHeader].[ShipDate],[Sales].[SalesOrderHeader].[Status],[Sales].[SalesOrderHeader].[OnlineOrderFlag],[Sales].[SalesOrderHeader].[SalesOrderNumber],[Sales].[SalesOrderHeader].[PurchaseOrderNumber],[Sales].[SalesOrderHeader].[AccountNumber],[Sales].[SalesOrderHeader].[CustomerID],[Sales].[SalesOrderHeader].[ContactID],[Sales].[SalesOrderHeader].[SalesPersonID],[Sales].[SalesOrderHeader].[TerritoryID],[Sales].[SalesOrderHeader].[BillToAddressID],[Sales].[SalesOrderHeader].[ShipToAddressID],[Sales].[SalesOrderHeader].[ShipMethodID],[Sales].[SalesOrderHeader].[CreditCardID],[Sales].[SalesOrderHeader].[CreditCardApprovalCode],[Sales].[SalesOrderHeader].[CurrencyRateID],[Sales].[SalesOrderHeader].[SubTotal],[Sales].[SalesOrderHeader].[TaxAmt],[Sales].[SalesOrderHeader].[Freight],[Sales].[SalesOrderHeader].[TotalDue],[Sales].[SalesOrderHeader].[Comment],[Sales].[SalesOrderHeader].[rowguid],[Sales].[SalesOrderHeader].[ModifiedDate] FROM [Sales].[SalesOrderHeader] WHERE [Sales].[SalesOrderHeader].[OrderDate] = '1/1/2003' AND [Sales].[SalesOrderHeader].[OrderDate] = '12/31/2003'</QueryDefinition></Source><StorageMode>Molap</StorageMode><ProcessingMode>Regular</ProcessingMode><ProactiveCaching><SilenceInterval>-PT1S</SilenceInterval><Latency>-PT1S</Latency><SilenceOverrideInterval>-PT1S</SilenceOverrideInterval><ForceRebuildInterval>P1D</ForceRebuildInterval><Enabled>true</Enabled><OnlineMode>OnCacheComplete</OnlineMode><AggregationStorage>MolapOnly</AggregationStorage><Source xsi:type=\"ProactiveCachingInheritedBinding\"><NotificationTechnique>Server</NotificationTechnique></Source></ProactiveCaching><EstimatedRows>1379</EstimatedRows><AggregationDesignID>AggregationDesign</AggregationDesignID></Partition></ObjectDefinition></Create>"

2/22/2011
 · 
 
by
DevinKnight
DevinKnight said:

You may be having escape sequence issues.  Replace your dates with variables

2/23/2011
 · 
 
by
prashantm
prashantm said:

Hi Devin ,

 

I am also facing same issue like Anil . Could you please help me  ?

here is my code

"<Create xmlns=\"http://schemas.microsoft.com/analysisservices/2003/engine\"><ParentObject><DatabaseID>AW_SSAS</DatabaseID><CubeID>Dsv Adventure Works</CubeID><MeasureGroupID>Sales Order Header</MeasureGroupID></ParentObject><ObjectDefinition><Partition xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><ID>SalesOrderHeader-2003</ID><Name>SalesOrderHeader-2003</Name><Annotations><Annotation><Name>AggregationPercent</Name><Value>25</Value></Annotation></Annotations><Source xsi:type=\"QueryBinding\"><DataSourceID>dsAdventureWorks</DataSourceID><QueryDefinition>SELECT [Sales].[SalesOrderHeader].[SalesOrderID],[Sales].[SalesOrderHeader].[RevisionNumber],[Sales].[SalesOrderHeader].[OrderDate],[Sales].[SalesOrderHeader].[DueDate],[Sales].[SalesOrderHeader].[ShipDate],[Sales].[SalesOrderHeader].[Status],[Sales].[SalesOrderHeader].[OnlineOrderFlag],[Sales].[SalesOrderHeader].[SalesOrderNumber],[Sales].[SalesOrderHeader].[PurchaseOrderNumber],[Sales].[SalesOrderHeader].[AccountNumber],[Sales].[SalesOrderHeader].[CustomerID],[Sales].[SalesOrderHeader].[ContactID],[Sales].[SalesOrderHeader].[SalesPersonID],[Sales].[SalesOrderHeader].[TerritoryID],[Sales].[SalesOrderHeader].[BillToAddressID],[Sales].[SalesOrderHeader].[ShipToAddressID],[Sales].[SalesOrderHeader].[ShipMethodID],[Sales].[SalesOrderHeader].[CreditCardID],[Sales].[SalesOrderHeader].[CreditCardApprovalCode],[Sales].[SalesOrderHeader].[CurrencyRateID],[Sales].[SalesOrderHeader].[SubTotal],[Sales].[SalesOrderHeader].[TaxAmt],[Sales].[SalesOrderHeader].[Freight],[Sales].[SalesOrderHeader].[TotalDue],[Sales].[SalesOrderHeader].[Comment],[Sales].[SalesOrderHeader].[rowguid],[Sales].[SalesOrderHeader].[ModifiedDate] FROM [Sales].[SalesOrderHeader] WHERE [Sales].[SalesOrderHeader].[OrderDate] = '1/1/2003' AND [Sales].[SalesOrderHeader].[OrderDate] = '12/31/2003'</QueryDefinition></Source><StorageMode>Molap</StorageMode><ProcessingMode>Regular</ProcessingMode><ProactiveCaching><SilenceInterval>-PT1S</SilenceInterval><Latency>-PT1S</Latency><SilenceOverrideInterval>-PT1S</SilenceOverrideInterval><ForceRebuildInterval>P1D</ForceRebuildInterval><Enabled>true</Enabled><OnlineMode>OnCacheComplete</OnlineMode><AggregationStorage>MolapOnly</AggregationStorage><Source xsi:type=\"ProactiveCachingInheritedBinding\"><NotificationTechnique>Server</NotificationTechnique></Source></ProactiveCaching><EstimatedRows>1379</EstimatedRows><AggregationDesignID>AggregationDesign</AggregationDesignID></Partition></ObjectDefinition></Create>"

2/23/2011
 · 
 
by
meganathank
meganathank said:

Innovative Approach, Thanks Devin

4/13/2011
 · 
 
by

Most Recent Articles