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.
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
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.
Hi Devin,
Scope value is not editable . How did you describe scope as a "CreatePartitions" ?
Regards,
Prashant Mhaske
CreatePartitions is just the name of the SSIS package. So the scope is the entire package.
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>"
You may be having escape sequence issues. Replace your dates with variables
Innovative Approach, Thanks Devin