AsPartitionProcessing
This commit is contained in:
commit
1395870498
63
.gitattributes
vendored
Normal file
63
.gitattributes
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
###############################################################################
|
||||
* text=auto
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
###############################################################################
|
||||
#*.cs diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
242
.gitignore
vendored
Normal file
242
.gitignore
vendored
Normal file
@ -0,0 +1,242 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
[Xx]64/
|
||||
[Xx]86/
|
||||
[Bb]uild/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# DNX
|
||||
project.lock.json
|
||||
artifacts/
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
|
||||
# TODO: Un-comment the next line if you do not want to checkin
|
||||
# your web deploy settings because they may include unencrypted
|
||||
# passwords
|
||||
#*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/packages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/packages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/packages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignoreable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
[Ss]tyle[Cc]op.*
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
orleans.codegen.cs
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# LightSwitch generated files
|
||||
GeneratedArtifacts/
|
||||
ModelManifest.xml
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
BIN
AsPartitionProcessing/AdventureWorksDW.bak
Normal file
BIN
AsPartitionProcessing/AdventureWorksDW.bak
Normal file
Binary file not shown.
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Development</Configuration>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{7274efcc-e7df-40ad-83df-1dfd5b954e67}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>MyRootNamespace</RootNamespace>
|
||||
<AssemblyName>MyAssemblyName</AssemblyName>
|
||||
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<Name>AsPartitionProcessing.AdventureWorks</Name>
|
||||
<DeploymentServerName>localhost</DeploymentServerName>
|
||||
<DeploymentServerEdition>Developer</DeploymentServerEdition>
|
||||
<DeploymentServerVersion>Version_11_0</DeploymentServerVersion>
|
||||
<DeploymentServerDatabase>AW Tabular Model SQL 2014</DeploymentServerDatabase>
|
||||
<DeploymentServerCubeName>Model</DeploymentServerCubeName>
|
||||
<DeploymentOptionProcessing>Default</DeploymentOptionProcessing>
|
||||
<DeploymentOptionTransactionalDeployment>False</DeploymentOptionTransactionalDeployment>
|
||||
<DeploymentOptionDirectQueryMode>InMemory</DeploymentOptionDirectQueryMode>
|
||||
<DeploymentOptionQueryImpersonation>Default</DeploymentOptionQueryImpersonation>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Development' ">
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DeploymentServerName>localhost</DeploymentServerName>
|
||||
<DeploymentServerEdition>Developer</DeploymentServerEdition>
|
||||
<DeploymentServerVersion>Version_11_0</DeploymentServerVersion>
|
||||
<DeploymentServerDatabase>AdventureWorks</DeploymentServerDatabase>
|
||||
<DeploymentServerCubeName>Model</DeploymentServerCubeName>
|
||||
<DeploymentOptionProcessing>Default</DeploymentOptionProcessing>
|
||||
<DeploymentOptionTransactionalDeployment>False</DeploymentOptionTransactionalDeployment>
|
||||
<DeploymentOptionDirectQueryMode>InMemory</DeploymentOptionDirectQueryMode>
|
||||
<DeploymentOptionQueryImpersonation>Default</DeploymentOptionQueryImpersonation>
|
||||
</PropertyGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<Compile Include="Model.bim">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Business Intelligence Semantic Model\1.0\Microsoft.AnalysisServices.VSHostBuilder.targets" />
|
||||
</Project>
|
6009
AsPartitionProcessing/AsPartitionProcessing.AdventureWorks/Model.bim
Normal file
6009
AsPartitionProcessing/AsPartitionProcessing.AdventureWorks/Model.bim
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<configSections>
|
||||
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
|
||||
<section name="AsPartitionProcessing.SampleClient.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
|
||||
</sectionGroup>
|
||||
</configSections>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/>
|
||||
</startup>
|
||||
<userSettings>
|
||||
<AsPartitionProcessing.SampleClient.Settings>
|
||||
<setting name="ConfigServer" serializeAs="String">
|
||||
<value>localhost</value>
|
||||
</setting>
|
||||
<setting name="ConfigDatabase" serializeAs="String">
|
||||
<value>AsPartitionProcessing</value>
|
||||
</setting>
|
||||
<setting name="ConfigDatabaseIntegratedAuth" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
</AsPartitionProcessing.SampleClient.Settings>
|
||||
</userSettings>
|
||||
</configuration>
|
@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{C45B329D-F606-4F89-A41A-785C247F24B2}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>AsPartitionProcessing.SampleClient</RootNamespace>
|
||||
<AssemblyName>AsPartitionProcessing.SampleClient</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.AnalysisServices, Version=13.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Microsoft SQL Server\130\SDK\Assemblies\Microsoft.AnalysisServices.DLL</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AnalysisServices.Core, Version=13.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Microsoft SQL Server\130\SDK\Assemblies\Microsoft.AnalysisServices.Core.DLL</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AnalysisServices.Tabular, Version=13.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Microsoft SQL Server\130\SDK\Assemblies\Microsoft.AnalysisServices.Tabular.DLL</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AsPartitionProcessing\AsPartitionProcessing.csproj">
|
||||
<Project>{fb937281-b06d-47fb-9846-e97b0287afce}</Project>
|
||||
<Name>AsPartitionProcessing</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
@ -0,0 +1,234 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AnalysisServices.Tabular;
|
||||
|
||||
|
||||
namespace AsPartitionProcessing.SampleClient
|
||||
{
|
||||
class Program
|
||||
{
|
||||
const bool UseDatabase = false;
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
List<PartitionedModelConfig> modelsConfig;
|
||||
if (!UseDatabase)
|
||||
{
|
||||
modelsConfig = InitializeAdventureWorksInline();
|
||||
}
|
||||
else
|
||||
{
|
||||
modelsConfig = InitializeFromDatabase();
|
||||
}
|
||||
|
||||
foreach (PartitionedModelConfig modelConfig in modelsConfig)
|
||||
{
|
||||
if (!modelConfig.IntegratedAuth) //For Azure AS
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.Write("User name for AS server: ");
|
||||
modelConfig.UserName = Console.ReadLine();
|
||||
Console.Write("Password for AS server: ");
|
||||
modelConfig.Password = ReadPassword();
|
||||
}
|
||||
|
||||
//Most important method:
|
||||
PartitionProcessor.PerformProcessing(modelConfig, LogMessage);
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(exc.Message, null);
|
||||
}
|
||||
|
||||
Console.WriteLine("Press any key to exit.");
|
||||
Console.ReadKey();
|
||||
}
|
||||
|
||||
private static List<PartitionedModelConfig> InitializeAdventureWorksInline()
|
||||
{
|
||||
PartitionedModelConfig partitionedModel = new PartitionedModelConfig(
|
||||
partitionedModelConfigID: 1,
|
||||
analysisServicesServer: "localhost",
|
||||
analysisServicesDatabase: "AdventureWorks",
|
||||
initialSetUp: true,
|
||||
incrementalOnline: true,
|
||||
incrementalParallelTables: true,
|
||||
integratedAuth: true,
|
||||
userName: "",
|
||||
password: "",
|
||||
partitionedTables:
|
||||
new List<PartitionedTableConfig>
|
||||
{
|
||||
new PartitionedTableConfig(
|
||||
partitionedTableConfigID: 1,
|
||||
maxDate: Convert.ToDateTime("2012-12-01"),
|
||||
granularity: Granularity.Monthly,
|
||||
numberOfPartitionsFull: 12,
|
||||
numberOfPartitionsForIncrementalProcess: 3,
|
||||
analysisServicesTable: "Internet Sales",
|
||||
sourceTableName: "[dbo].[FactInternetSales]",
|
||||
sourcePartitionColumn: "OrderDateKey"
|
||||
),
|
||||
new PartitionedTableConfig(
|
||||
partitionedTableConfigID: 2,
|
||||
maxDate: Convert.ToDateTime("2012-12-01"),
|
||||
granularity: Granularity.Yearly,
|
||||
numberOfPartitionsFull: 3,
|
||||
numberOfPartitionsForIncrementalProcess: 1,
|
||||
analysisServicesTable: "Reseller Sales",
|
||||
sourceTableName: "[dbo].[FactResellerSales]",
|
||||
sourcePartitionColumn: "OrderDateKey"
|
||||
)
|
||||
}
|
||||
);
|
||||
|
||||
#region Not needed as sample includes pre-prepared version of AdventureWorks
|
||||
|
||||
////This section not to be used normally - just to get started with AdventureWorks. It removes existing partitions that come in AdventureWorks and creates a template one to align with assumptions listed at top of PartitionProcessor.cs file.
|
||||
//if (partitionedModel.InitialSetUp)
|
||||
//{
|
||||
// Console.WriteLine("Initialize AdventureWorks template partitions? [y/n]");
|
||||
// if (Console.ReadLine().ToLower() == "y")
|
||||
// InitializeAdventureWorksDatabase(partitionedModel);
|
||||
//}
|
||||
|
||||
#endregion
|
||||
|
||||
return new List<PartitionedModelConfig> { partitionedModel };
|
||||
}
|
||||
|
||||
private static List<PartitionedModelConfig> InitializeFromDatabase()
|
||||
{
|
||||
ConfigDatabaseConnectionInfo connectionInfo = new ConfigDatabaseConnectionInfo();
|
||||
|
||||
connectionInfo.Server = Settings.Default.ConfigServer;
|
||||
connectionInfo.Database = Settings.Default.ConfigDatabase;
|
||||
connectionInfo.IntegratedAuth = Settings.Default.ConfigDatabaseIntegratedAuth;
|
||||
|
||||
if (!Settings.Default.ConfigDatabaseIntegratedAuth)
|
||||
{
|
||||
Console.Write("User name for config database: ");
|
||||
connectionInfo.UserName = Console.ReadLine();
|
||||
Console.Write("Password for config database: ");
|
||||
connectionInfo.Password = ReadPassword();
|
||||
}
|
||||
|
||||
return ConfigDatabaseHelper.ReadConfig(connectionInfo);
|
||||
}
|
||||
|
||||
private static void LogMessage(string message, PartitionedModelConfig partitionedModel)
|
||||
{
|
||||
//Can provide custom logger here
|
||||
try
|
||||
{
|
||||
if (UseDatabase)
|
||||
ConfigDatabaseHelper.LogMessage(message, partitionedModel);
|
||||
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
Console.WriteLine(exc.Message);
|
||||
Console.WriteLine("Press any key to exit.");
|
||||
Console.ReadKey();
|
||||
Environment.Exit(0); //Avoid recursion if errored connecting to db
|
||||
}
|
||||
}
|
||||
|
||||
public static string ReadPassword()
|
||||
{
|
||||
string password = "";
|
||||
ConsoleKeyInfo info = Console.ReadKey(true);
|
||||
while (info.Key != ConsoleKey.Enter)
|
||||
{
|
||||
if (info.Key != ConsoleKey.Backspace)
|
||||
{
|
||||
Console.Write("*");
|
||||
password += info.KeyChar;
|
||||
}
|
||||
else if (info.Key == ConsoleKey.Backspace)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(password))
|
||||
{
|
||||
// remove one character from the list of password characters
|
||||
password = password.Substring(0, password.Length - 1);
|
||||
// get the location of the cursor
|
||||
int pos = Console.CursorLeft;
|
||||
// move the cursor to the left by one character
|
||||
Console.SetCursorPosition(pos - 1, Console.CursorTop);
|
||||
// replace it with space
|
||||
Console.Write(" ");
|
||||
// move the cursor to the left by one character again
|
||||
Console.SetCursorPosition(pos - 1, Console.CursorTop);
|
||||
}
|
||||
}
|
||||
info = Console.ReadKey(true);
|
||||
}
|
||||
// add a new line because user pressed enter at the end of password
|
||||
Console.WriteLine();
|
||||
return password;
|
||||
}
|
||||
|
||||
#region Not needed as sample includes pre-prepared version of AdventureWorks
|
||||
|
||||
private static void InitializeAdventureWorksDatabase(PartitionedModelConfig parameters)
|
||||
{
|
||||
//In order to align with assumptions listed in PartitionProcessor.cs, need to:
|
||||
//1. Delete existing partitions in InternetSales and ResellerSales
|
||||
//2. Create template partition (again, see comments at top of PartitionProcessor.cs)
|
||||
|
||||
Console.WriteLine("Initializing AdventureWorks ...");
|
||||
|
||||
using (Server server = new Server())
|
||||
{
|
||||
//Connect and get main objects
|
||||
string serverConnectionString;
|
||||
if (parameters.IntegratedAuth)
|
||||
serverConnectionString = $"Provider=MSOLAP;Data Source={parameters.AnalysisServicesServer};";
|
||||
else
|
||||
{
|
||||
serverConnectionString = $"Provider=MSOLAP;Data Source={parameters.AnalysisServicesServer};User ID={parameters.UserName};Password={parameters.Password};Persist Security Info=True;Impersonation Level=Impersonate;";
|
||||
}
|
||||
server.Connect(serverConnectionString);
|
||||
|
||||
Database database = server.Databases.FindByName(parameters.AnalysisServicesDatabase);
|
||||
if (database == null)
|
||||
{
|
||||
throw new Microsoft.AnalysisServices.ConnectionException($"Could not connect to database {parameters.AnalysisServicesDatabase}.");
|
||||
}
|
||||
|
||||
InitializeAdventureWorksTable(database, "Internet Sales", "[dbo].[FactInternetSales]");
|
||||
InitializeAdventureWorksTable(database, "Reseller Sales", "[dbo].[FactResellerSales]");
|
||||
|
||||
database.Update(Microsoft.AnalysisServices.UpdateOptions.ExpandFull);
|
||||
server.Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
private static void InitializeAdventureWorksTable(Database database, string analysisServicesTableName, string sourceFactTableName)
|
||||
{
|
||||
Table table = database.Model.Tables.Find(analysisServicesTableName);
|
||||
if (table == null)
|
||||
{
|
||||
throw new Microsoft.AnalysisServices.ConnectionException($"Could not connect to table {analysisServicesTableName}.");
|
||||
}
|
||||
table.Partitions.Clear();
|
||||
Partition templatePartition = new Partition();
|
||||
templatePartition.Name = analysisServicesTableName;
|
||||
table.Partitions.Add(templatePartition);
|
||||
templatePartition.Source = new QueryPartitionSource()
|
||||
{
|
||||
DataSource = database.Model.DataSources[0], //Assuming this is only data source (SqlServer localhost)
|
||||
Query = $"SELECT * FROM {sourceFactTableName}"
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("AsPartitionProcessing.SampleClient")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft Corporation")]
|
||||
[assembly: AssemblyProduct("AsPartitionProcessing.SampleClient")]
|
||||
[assembly: AssemblyCopyright("Copyright © Microsoft Corporation 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("c45b329d-f606-4f89-a41a-785c247f24b2")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
62
AsPartitionProcessing/AsPartitionProcessing.SampleClient/Settings.Designer.cs
generated
Normal file
62
AsPartitionProcessing/AsPartitionProcessing.SampleClient/Settings.Designer.cs
generated
Normal file
@ -0,0 +1,62 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace AsPartitionProcessing.SampleClient {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default {
|
||||
get {
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("localhost")]
|
||||
public string ConfigServer {
|
||||
get {
|
||||
return ((string)(this["ConfigServer"]));
|
||||
}
|
||||
set {
|
||||
this["ConfigServer"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("AsPartitionProcessing")]
|
||||
public string ConfigDatabase {
|
||||
get {
|
||||
return ((string)(this["ConfigDatabase"]));
|
||||
}
|
||||
set {
|
||||
this["ConfigDatabase"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool ConfigDatabaseIntegratedAuth {
|
||||
get {
|
||||
return ((bool)(this["ConfigDatabaseIntegratedAuth"]));
|
||||
}
|
||||
set {
|
||||
this["ConfigDatabaseIntegratedAuth"] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="AsPartitionProcessing.SampleClient" GeneratedClassName="Settings">
|
||||
<Profiles />
|
||||
<Settings>
|
||||
<Setting Name="ConfigServer" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">localhost</Value>
|
||||
</Setting>
|
||||
<Setting Name="ConfigDatabase" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">AsPartitionProcessing</Value>
|
||||
</Setting>
|
||||
<Setting Name="ConfigDatabaseIntegratedAuth" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
</Settings>
|
||||
</SettingsFile>
|
73
AsPartitionProcessing/AsPartitionProcessing.sln
Normal file
73
AsPartitionProcessing/AsPartitionProcessing.sln
Normal file
@ -0,0 +1,73 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AsPartitionProcessing", "AsPartitionProcessing\AsPartitionProcessing.csproj", "{FB937281-B06D-47FB-9846-E97B0287AFCE}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AsPartitionProcessing.SampleClient", "AsPartitionProcessing.SampleClient\AsPartitionProcessing.SampleClient.csproj", "{C45B329D-F606-4F89-A41A-785C247F24B2}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0B23151E-8A6B-44AA-B670-797D1EB8B3C0}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
AdventureWorksDW.bak = AdventureWorksDW.bak
|
||||
CreateDatabaseObjects.sql = CreateDatabaseObjects.sql
|
||||
SampleConfiguration.sql = SampleConfiguration.sql
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{6870E480-7721-4708-BFB8-9AE898AA21B3}") = "AsPartitionProcessing.AdventureWorks", "AsPartitionProcessing.AdventureWorks\AsPartitionProcessing.AdventureWorks.smproj", "{7274EFCC-E7DF-40AD-83DF-1DFD5B954E67}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x86 = Debug|x86
|
||||
Development|Any CPU = Development|Any CPU
|
||||
Development|x86 = Development|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{FB937281-B06D-47FB-9846-E97B0287AFCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FB937281-B06D-47FB-9846-E97B0287AFCE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FB937281-B06D-47FB-9846-E97B0287AFCE}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{FB937281-B06D-47FB-9846-E97B0287AFCE}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{FB937281-B06D-47FB-9846-E97B0287AFCE}.Development|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FB937281-B06D-47FB-9846-E97B0287AFCE}.Development|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FB937281-B06D-47FB-9846-E97B0287AFCE}.Development|x86.ActiveCfg = Debug|Any CPU
|
||||
{FB937281-B06D-47FB-9846-E97B0287AFCE}.Development|x86.Build.0 = Debug|Any CPU
|
||||
{FB937281-B06D-47FB-9846-E97B0287AFCE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FB937281-B06D-47FB-9846-E97B0287AFCE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FB937281-B06D-47FB-9846-E97B0287AFCE}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{FB937281-B06D-47FB-9846-E97B0287AFCE}.Release|x86.Build.0 = Release|Any CPU
|
||||
{C45B329D-F606-4F89-A41A-785C247F24B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C45B329D-F606-4F89-A41A-785C247F24B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C45B329D-F606-4F89-A41A-785C247F24B2}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{C45B329D-F606-4F89-A41A-785C247F24B2}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{C45B329D-F606-4F89-A41A-785C247F24B2}.Development|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C45B329D-F606-4F89-A41A-785C247F24B2}.Development|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C45B329D-F606-4F89-A41A-785C247F24B2}.Development|x86.ActiveCfg = Debug|Any CPU
|
||||
{C45B329D-F606-4F89-A41A-785C247F24B2}.Development|x86.Build.0 = Debug|Any CPU
|
||||
{C45B329D-F606-4F89-A41A-785C247F24B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C45B329D-F606-4F89-A41A-785C247F24B2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C45B329D-F606-4F89-A41A-785C247F24B2}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C45B329D-F606-4F89-A41A-785C247F24B2}.Release|x86.Build.0 = Release|Any CPU
|
||||
{7274EFCC-E7DF-40AD-83DF-1DFD5B954E67}.Debug|Any CPU.ActiveCfg = Development|x86
|
||||
{7274EFCC-E7DF-40AD-83DF-1DFD5B954E67}.Debug|Any CPU.Build.0 = Development|x86
|
||||
{7274EFCC-E7DF-40AD-83DF-1DFD5B954E67}.Debug|Any CPU.Deploy.0 = Development|x86
|
||||
{7274EFCC-E7DF-40AD-83DF-1DFD5B954E67}.Debug|x86.ActiveCfg = Development|x86
|
||||
{7274EFCC-E7DF-40AD-83DF-1DFD5B954E67}.Debug|x86.Build.0 = Development|x86
|
||||
{7274EFCC-E7DF-40AD-83DF-1DFD5B954E67}.Debug|x86.Deploy.0 = Development|x86
|
||||
{7274EFCC-E7DF-40AD-83DF-1DFD5B954E67}.Development|Any CPU.ActiveCfg = Development|x86
|
||||
{7274EFCC-E7DF-40AD-83DF-1DFD5B954E67}.Development|x86.ActiveCfg = Development|x86
|
||||
{7274EFCC-E7DF-40AD-83DF-1DFD5B954E67}.Development|x86.Build.0 = Development|x86
|
||||
{7274EFCC-E7DF-40AD-83DF-1DFD5B954E67}.Development|x86.Deploy.0 = Development|x86
|
||||
{7274EFCC-E7DF-40AD-83DF-1DFD5B954E67}.Release|Any CPU.ActiveCfg = Development|x86
|
||||
{7274EFCC-E7DF-40AD-83DF-1DFD5B954E67}.Release|Any CPU.Build.0 = Development|x86
|
||||
{7274EFCC-E7DF-40AD-83DF-1DFD5B954E67}.Release|Any CPU.Deploy.0 = Development|x86
|
||||
{7274EFCC-E7DF-40AD-83DF-1DFD5B954E67}.Release|x86.ActiveCfg = Development|x86
|
||||
{7274EFCC-E7DF-40AD-83DF-1DFD5B954E67}.Release|x86.Build.0 = Development|x86
|
||||
{7274EFCC-E7DF-40AD-83DF-1DFD5B954E67}.Release|x86.Deploy.0 = Development|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{FB937281-B06D-47FB-9846-E97B0287AFCE}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>AsPartitionProcessing</RootNamespace>
|
||||
<AssemblyName>AsPartitionProcessing</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DocumentationFile>bin\Release\AsPartitionProcessing.XML</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.AnalysisServices, Version=13.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Microsoft SQL Server\130\SDK\Assemblies\Microsoft.AnalysisServices.DLL</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AnalysisServices.Core, Version=13.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Microsoft SQL Server\130\SDK\Assemblies\Microsoft.AnalysisServices.Core.DLL</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AnalysisServices.Tabular, Version=13.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Microsoft SQL Server\130\SDK\Assemblies\Microsoft.AnalysisServices.Tabular.DLL</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ConfigDatabaseConnectionInfo.cs" />
|
||||
<Compile Include="PartitionedModelConfig.cs" />
|
||||
<Compile Include="ConfigDatabaseHelper.cs" />
|
||||
<Compile Include="PartitionedTableConfig.cs" />
|
||||
<Compile Include="PartitionProcessor.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
@ -0,0 +1,35 @@
|
||||
using System;
|
||||
|
||||
namespace AsPartitionProcessing
|
||||
{
|
||||
/// <summary>
|
||||
/// Information required to connect to the configuration and logging database.
|
||||
/// </summary>
|
||||
public class ConfigDatabaseConnectionInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Database server name.
|
||||
/// </summary>
|
||||
public string Server { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the database.
|
||||
/// </summary>
|
||||
public string Database { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User name used for connection.
|
||||
/// </summary>
|
||||
public string UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Password used for connection.
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether connection to be made using integrated authentication or SQL authentication.
|
||||
/// </summary>
|
||||
public bool IntegratedAuth { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,173 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Data.SqlClient;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AsPartitionProcessing
|
||||
{
|
||||
/// <summary>
|
||||
/// Class containing helper methods for reading and writing to the configuration and logging database.
|
||||
/// </summary>
|
||||
public static class ConfigDatabaseHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Read configuration information from the database.
|
||||
/// </summary>
|
||||
/// <param name="connectionInfo">Information required to connect to the configuration and logging database.</param>
|
||||
/// <returns>Collection of partitioned models with configuration information.</returns>
|
||||
public static List<PartitionedModelConfig> ReadConfig(ConfigDatabaseConnectionInfo connectionInfo)
|
||||
{
|
||||
using (SqlConnection connection = new SqlConnection(GetConnectionString(connectionInfo)))
|
||||
{
|
||||
connection.Open();
|
||||
using (SqlCommand command = new SqlCommand())
|
||||
{
|
||||
command.Connection = connection;
|
||||
command.CommandType = CommandType.Text;
|
||||
command.CommandText = @"
|
||||
SELECT [PartitionedModelConfigID]
|
||||
,[AnalysisServicesServer]
|
||||
,[AnalysisServicesDatabase]
|
||||
,[InitialSetUp]
|
||||
,[IncrementalOnline]
|
||||
,[IncrementalParallelTables]
|
||||
,[IntegratedAuth]
|
||||
,[PartitionedTableConfigID]
|
||||
,[MaxDate]
|
||||
,[Granularity]
|
||||
,[NumberOfPartitionsFull]
|
||||
,[NumberOfPartitionsForIncrementalProcess]
|
||||
,[AnalysisServicesTable]
|
||||
,[SourceTableName]
|
||||
,[SourcePartitionColumn]
|
||||
FROM [dbo].[vPartitionedTableConfig]
|
||||
ORDER BY [PartitionedModelConfigID], [PartitionedTableConfigID];";
|
||||
|
||||
List<PartitionedModelConfig> models = new List<PartitionedModelConfig>();
|
||||
PartitionedModelConfig modelConfig = null;
|
||||
int currentPartitionedModelConfigID = -1;
|
||||
|
||||
SqlDataReader reader = command.ExecuteReader();
|
||||
while (reader.Read())
|
||||
{
|
||||
if (modelConfig == null || currentPartitionedModelConfigID != Convert.ToInt32(reader["PartitionedModelConfigID"]))
|
||||
{
|
||||
modelConfig = new PartitionedModelConfig();
|
||||
modelConfig.PartitionedTables = new List<PartitionedTableConfig>();
|
||||
models.Add(modelConfig);
|
||||
|
||||
modelConfig.PartitionedModelConfigID = Convert.ToInt32(reader["PartitionedModelConfigID"]);
|
||||
modelConfig.AnalysisServicesServer = Convert.ToString(reader["AnalysisServicesServer"]);
|
||||
modelConfig.AnalysisServicesDatabase = Convert.ToString(reader["AnalysisServicesDatabase"]);
|
||||
modelConfig.InitialSetUp = Convert.ToBoolean(reader["InitialSetUp"]);
|
||||
modelConfig.IncrementalOnline = Convert.ToBoolean(reader["IncrementalOnline"]);
|
||||
modelConfig.IncrementalParallelTables = Convert.ToBoolean(reader["IncrementalParallelTables"]);
|
||||
modelConfig.IntegratedAuth = Convert.ToBoolean(reader["IntegratedAuth"]);
|
||||
modelConfig.ConfigDatabaseConnectionInfo = connectionInfo;
|
||||
|
||||
currentPartitionedModelConfigID = modelConfig.PartitionedModelConfigID;
|
||||
}
|
||||
|
||||
modelConfig.PartitionedTables.Add(
|
||||
new PartitionedTableConfig(
|
||||
Convert.ToInt32(reader["PartitionedTableConfigID"]),
|
||||
Convert.ToDateTime(reader["MaxDate"]),
|
||||
(Granularity)Convert.ToInt32(reader["Granularity"]),
|
||||
Convert.ToInt32(reader["NumberOfPartitionsFull"]),
|
||||
Convert.ToInt32(reader["NumberOfPartitionsForIncrementalProcess"]),
|
||||
Convert.ToString(reader["AnalysisServicesTable"]),
|
||||
Convert.ToString(reader["SourceTableName"]),
|
||||
Convert.ToString(reader["SourcePartitionColumn"])
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return models;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete all existing logs from the database. Useful in demo scenarios to initialize the database.
|
||||
/// </summary>
|
||||
/// <param name="connectionInfo">Information required to connect to the configuration and logging database.</param>
|
||||
public static void ClearLogTable(ConfigDatabaseConnectionInfo connectionInfo)
|
||||
{
|
||||
using (var connection = new SqlConnection(GetConnectionString(connectionInfo)))
|
||||
{
|
||||
connection.Open();
|
||||
using (var command = new SqlCommand())
|
||||
{
|
||||
command.Connection = connection;
|
||||
command.CommandType = CommandType.Text;
|
||||
command.CommandText = "DELETE FROM [dbo].[PartitionedModelLog];";
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log a message to the databsae.
|
||||
/// </summary>
|
||||
/// <param name="message">Message to be logged.</param>
|
||||
/// <param name="partitionedModel">Partitioned model with configuration information.</param>
|
||||
public static void LogMessage(string message, PartitionedModelConfig partitionedModel)
|
||||
{
|
||||
using (var connection = new SqlConnection(GetConnectionString(partitionedModel.ConfigDatabaseConnectionInfo)))
|
||||
{
|
||||
connection.Open();
|
||||
using (var command = new SqlCommand())
|
||||
{
|
||||
command.Connection = connection;
|
||||
command.CommandType = CommandType.Text;
|
||||
command.CommandText = @"
|
||||
INSERT INTO [dbo].[PartitionedModelLog]
|
||||
([PartitionedModelConfigID]
|
||||
,[ExecutionID]
|
||||
,[LogDateTime]
|
||||
,[Message])
|
||||
VALUES
|
||||
(@PartitionedModelConfigID
|
||||
,@ExecutionID
|
||||
,@LogDateTime
|
||||
,@Message);";
|
||||
|
||||
SqlParameter parameter;
|
||||
|
||||
parameter = new SqlParameter("@PartitionedModelConfigID", SqlDbType.Int);
|
||||
parameter.Value = partitionedModel.PartitionedModelConfigID;
|
||||
command.Parameters.Add(parameter);
|
||||
|
||||
parameter = new SqlParameter("@ExecutionID", SqlDbType.Char, 36);
|
||||
parameter.Value = partitionedModel.ExecutionID;
|
||||
command.Parameters.Add(parameter);
|
||||
|
||||
parameter = new SqlParameter("@LogDateTime", SqlDbType.DateTime);
|
||||
parameter.Value = DateTime.Now;
|
||||
command.Parameters.Add(parameter);
|
||||
|
||||
parameter = new SqlParameter("@Message", SqlDbType.VarChar, 4000);
|
||||
parameter.Value = message;
|
||||
command.Parameters.Add(parameter);
|
||||
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetConnectionString(ConfigDatabaseConnectionInfo connectionInfo)
|
||||
{
|
||||
string connectionString;
|
||||
if (connectionInfo.IntegratedAuth)
|
||||
{
|
||||
connectionString = $"Server={connectionInfo.Server};Database={connectionInfo.Database};Integrated Security=SSPI;";
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionString = $"Server={connectionInfo.Server};Database={connectionInfo.Database};User ID={connectionInfo.UserName};Password={connectionInfo.Password};";
|
||||
}
|
||||
|
||||
return connectionString;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace AsPartitionProcessing
|
||||
{
|
||||
public class LogMessageEventArgs : EventArgs
|
||||
{
|
||||
public string Message { get; set; }
|
||||
|
||||
public LogMessageEventArgs(string message)
|
||||
{
|
||||
Message = message;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,343 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AnalysisServices.Tabular;
|
||||
|
||||
|
||||
//-----------
|
||||
//ASSUMPTIONS
|
||||
//Rolling window. Removes oldest partition on increment
|
||||
//Depends on date keys in source to be integers formatted as yyyymmdd
|
||||
//Source queries take the form "SELECT * FROM <SourceTable> WHERE FLOOR(<SourceColumn> / 100) = <yyyymm>" (monthly)
|
||||
//Template partition exists with same name as table
|
||||
//Non-template partitions have name of the format yyyy (yearly), yyyymm (monthly), yyyymmdd (daily)
|
||||
//-----------
|
||||
|
||||
|
||||
namespace AsPartitionProcessing
|
||||
{
|
||||
/// <summary>
|
||||
/// Delegate to allow client to pass in a custom logging method
|
||||
/// </summary>
|
||||
/// <param name="message">The message to be logged</param>
|
||||
/// <param name="partitionedModel">Configuration info for the partitioned model</param>
|
||||
public delegate void LogMessageDelegate(string message, PartitionedModelConfig partitionedModel);
|
||||
|
||||
/// <summary>
|
||||
/// Processor of partitions in AS tabular models
|
||||
/// </summary>
|
||||
public static class PartitionProcessor
|
||||
{
|
||||
private static PartitionedModelConfig _partitionedModel;
|
||||
private static LogMessageDelegate _messageLogger;
|
||||
|
||||
/// <summary>
|
||||
/// Partitions tables in a tabular model based on configuration
|
||||
/// </summary>
|
||||
/// <param name="partitionedModel">Configuration info for the partitioned model</param>
|
||||
/// <param name="messageLogger">Pointer to logging method</param>
|
||||
public static void PerformProcessing(PartitionedModelConfig partitionedModel, LogMessageDelegate messageLogger)
|
||||
{
|
||||
_partitionedModel = partitionedModel;
|
||||
_messageLogger = messageLogger;
|
||||
|
||||
Server server = new Server();
|
||||
try
|
||||
{
|
||||
Database database;
|
||||
Connect(server, out database);
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
LogMessage($"Start: {DateTime.Now.ToString("hh:mm:ss tt")}", false);
|
||||
LogMessage($"Server: {_partitionedModel.AnalysisServicesServer}", false);
|
||||
|
||||
LogMessage($"Database: {_partitionedModel.AnalysisServicesDatabase}", false);
|
||||
|
||||
foreach (PartitionedTableConfig partitionedTable in _partitionedModel.PartitionedTables)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
|
||||
Table table = database.Model.Tables.Find(partitionedTable.AnalysisServicesTable);
|
||||
if (table == null)
|
||||
{
|
||||
throw new Microsoft.AnalysisServices.ConnectionException($"Could not connect to table {partitionedTable.AnalysisServicesTable}.");
|
||||
}
|
||||
Partition templatePartition = table.Partitions.Find(partitionedTable.AnalysisServicesTable);
|
||||
if (templatePartition == null)
|
||||
{
|
||||
throw new Microsoft.AnalysisServices.ConnectionException($"Table {partitionedTable.AnalysisServicesTable} does not contain a partition with the same name to act as the template partition.");
|
||||
}
|
||||
|
||||
LogMessage("", false);
|
||||
LogMessage($"Rolling-window partitioning for table {partitionedTable.AnalysisServicesTable}", false);
|
||||
LogMessage(new String('-', partitionedTable.AnalysisServicesTable.Length + 38), false);
|
||||
|
||||
//Figure out what processing needs to be done
|
||||
List<string> partitionKeysCurrent = GetPartitionKeysTable(table, partitionedTable.Granularity);
|
||||
List<string> partitionKeysNew = GetPartitionKeys(false, partitionedTable, partitionedTable.Granularity);
|
||||
List<string> partitionKeysForProcessing = GetPartitionKeys(true, partitionedTable, partitionedTable.Granularity);
|
||||
DisplayPartitionRange(partitionKeysCurrent, true, partitionedTable.Granularity);
|
||||
DisplayPartitionRange(partitionKeysNew, false, partitionedTable.Granularity);
|
||||
LogMessage("", false);
|
||||
LogMessage("=>Actions & progress:", false);
|
||||
|
||||
//Check for old partitions that need to be removed
|
||||
foreach (string partitionKey in partitionKeysCurrent)
|
||||
{
|
||||
if (Convert.ToInt32(partitionKey) < Convert.ToInt32(partitionKeysNew[0]))
|
||||
{
|
||||
LogMessage($"Remove old partition {DateFormatPartitionKey(partitionKey, partitionedTable.Granularity)}", true);
|
||||
table.Partitions.Remove(partitionKey);
|
||||
}
|
||||
}
|
||||
|
||||
//Process partitions
|
||||
string selectQueryTemplate;
|
||||
switch (partitionedTable.Granularity)
|
||||
{
|
||||
case Granularity.Daily:
|
||||
selectQueryTemplate = "SELECT * FROM {0} WHERE {1} = {2} ORDER BY {1}";
|
||||
break;
|
||||
case Granularity.Monthly:
|
||||
selectQueryTemplate = "SELECT * FROM {0} WHERE FLOOR({1} / 100) = {2} ORDER BY {1}";
|
||||
break;
|
||||
default: //Granularity.Yearly:
|
||||
selectQueryTemplate = "SELECT * FROM {0} WHERE FLOOR({1} / 10000) = {2} ORDER BY {1}";
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (string partitionKey in partitionKeysForProcessing)
|
||||
{
|
||||
Partition partitionToProcess = table.Partitions.Find(partitionKey);
|
||||
|
||||
if (partitionToProcess == null)
|
||||
{
|
||||
//Doesn't exist so create it
|
||||
partitionToProcess = new Partition();
|
||||
templatePartition.CopyTo(partitionToProcess);
|
||||
partitionToProcess.Name = partitionKey;
|
||||
((QueryPartitionSource)partitionToProcess.Source).Query = String.Format(selectQueryTemplate, partitionedTable.SourceTableName, partitionedTable.SourcePartitionColumn, partitionKey);
|
||||
table.Partitions.Add(partitionToProcess);
|
||||
LogMessage($"Create new partition {DateFormatPartitionKey(partitionKey, partitionedTable.Granularity)}", true);
|
||||
|
||||
if (!_partitionedModel.InitialSetUp)
|
||||
{
|
||||
IncrementalProcessPartition(partitionKey, partitionToProcess, partitionedTable.Granularity);
|
||||
}
|
||||
}
|
||||
else if (!_partitionedModel.InitialSetUp)
|
||||
{
|
||||
//Existing partition for processing
|
||||
IncrementalProcessPartition(partitionKey, partitionToProcess, partitionedTable.Granularity);
|
||||
}
|
||||
|
||||
if (_partitionedModel.InitialSetUp)
|
||||
{
|
||||
if (partitionToProcess.State != ObjectState.Ready)
|
||||
{
|
||||
//Process new partitions sequentially during initial setup so don't run out of memory
|
||||
LogMessage($"Sequentially process {DateFormatPartitionKey(partitionKey, partitionedTable.Granularity)} /DataOnly", true);
|
||||
partitionToProcess.RequestRefresh(RefreshType.DataOnly);
|
||||
database.Model.SaveChanges();
|
||||
}
|
||||
else
|
||||
{
|
||||
//Partition already exists during initial setup (and is fully processed), so ignore it
|
||||
LogMessage($"Partition {DateFormatPartitionKey(partitionKey, partitionedTable.Granularity)} already exists and is processed", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Ensure template partition doesn't contain any data
|
||||
if (_partitionedModel.InitialSetUp)
|
||||
{
|
||||
((QueryPartitionSource)templatePartition.Source).Query = String.Format("SELECT * FROM {0} WHERE 0=1", partitionedTable.SourceTableName);
|
||||
templatePartition.RequestRefresh(RefreshType.DataOnly);
|
||||
}
|
||||
|
||||
//If processing tables sequentially (but all partitions being done in parallel), then save changes now
|
||||
if (!_partitionedModel.IncrementalParallelTables)
|
||||
{
|
||||
LogMessage($"Save changes for table {partitionedTable.AnalysisServicesTable} ...", true);
|
||||
database.Model.SaveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
//Commit the data changes, and bring model back online if necessary
|
||||
|
||||
LogMessage("", false);
|
||||
LogMessage("Final operations", false);
|
||||
LogMessage(new String('-', 16), false);
|
||||
|
||||
if (_partitionedModel.IncrementalParallelTables)
|
||||
{
|
||||
LogMessage("Save changes ...", true);
|
||||
database.Model.SaveChanges();
|
||||
}
|
||||
|
||||
if (_partitionedModel.InitialSetUp || (!_partitionedModel.InitialSetUp && !_partitionedModel.IncrementalOnline))
|
||||
{
|
||||
LogMessage("Recalc model to bring back online ...", true);
|
||||
|
||||
database.Model.RequestRefresh(RefreshType.Calculate);
|
||||
database.Model.SaveChanges();
|
||||
}
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
LogMessage("", false);
|
||||
LogMessage("Finish: " + DateTime.Now.ToString("hh:mm:ss tt"), false);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
LogMessage("", false);
|
||||
LogMessage($"Exception occurred: {DateTime.Now.ToString("hh:mm:ss tt")}", false);
|
||||
LogMessage($"Exception message: {exc.Message}", false);
|
||||
LogMessage($"Inner exception message: {exc.InnerException.Message}", false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
_partitionedModel = null;
|
||||
_messageLogger = null;
|
||||
if (server != null) server.Disconnect();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
private static void IncrementalProcessPartition(string partitionKey, Partition partitionToProcess, Granularity granularity)
|
||||
{
|
||||
if (_partitionedModel.IncrementalOnline)
|
||||
{
|
||||
LogMessage($"Parallel process partition {DateFormatPartitionKey(partitionKey, granularity)} /Full", true);
|
||||
partitionToProcess.RequestRefresh(RefreshType.Full);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogMessage($"Parallel process partition {DateFormatPartitionKey(partitionKey, granularity)} /DataOnly", true);
|
||||
partitionToProcess.RequestRefresh(RefreshType.DataOnly);
|
||||
}
|
||||
}
|
||||
|
||||
private static void LogMessage(string message, bool indented)
|
||||
{
|
||||
_messageLogger($"{(indented ? new String(' ', 3) : "")}{message}", _partitionedModel);
|
||||
}
|
||||
|
||||
private static string DateFormatPartitionKey(string partitionKey, Granularity granularity)
|
||||
{
|
||||
string returnVal = partitionKey.Substring(0, 4);
|
||||
|
||||
try
|
||||
{
|
||||
if (granularity == Granularity.Monthly || granularity == Granularity.Daily)
|
||||
{
|
||||
returnVal += "-" + partitionKey.Substring(4, 2);
|
||||
}
|
||||
|
||||
if (granularity == Granularity.Daily)
|
||||
{
|
||||
returnVal += "-" + partitionKey.Substring(6, 2);
|
||||
}
|
||||
}
|
||||
catch (ArgumentOutOfRangeException exc)
|
||||
{
|
||||
throw new InvalidOperationException($"Failed to derive date from partition key. Check the key {partitionKey} matches {Convert.ToString(granularity)} granularity.");
|
||||
}
|
||||
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
private static void DisplayPartitionRange(List<string> partitionKeys, bool current, Granularity granularity)
|
||||
{
|
||||
LogMessage("", false);
|
||||
|
||||
if (partitionKeys.Count > 0)
|
||||
{
|
||||
LogMessage($"=>{(current ? "Current" : "New")} partition range ({Convert.ToString(granularity)}):", false);
|
||||
LogMessage($"MIN partition: {DateFormatPartitionKey(partitionKeys[0], granularity)}", true);
|
||||
LogMessage($"MAX partition: {DateFormatPartitionKey(partitionKeys[partitionKeys.Count - 1], granularity)}", true);
|
||||
LogMessage($"Partition count: {partitionKeys.Count}", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogMessage("=>Table not yet partitioned", false);
|
||||
}
|
||||
}
|
||||
|
||||
private static void Connect(Server server, out Database database)
|
||||
{
|
||||
//Connect and get main objects
|
||||
string serverConnectionString;
|
||||
if (_partitionedModel.IntegratedAuth)
|
||||
serverConnectionString = $"Provider=MSOLAP;Data Source={_partitionedModel.AnalysisServicesServer};";
|
||||
else
|
||||
{
|
||||
serverConnectionString = $"Provider=MSOLAP;Data Source={_partitionedModel.AnalysisServicesServer};User ID={_partitionedModel.UserName};Password={_partitionedModel.Password};Persist Security Info=True;Impersonation Level=Impersonate;";
|
||||
}
|
||||
server.Connect(serverConnectionString);
|
||||
|
||||
database = server.Databases.FindByName(_partitionedModel.AnalysisServicesDatabase);
|
||||
if (database == null)
|
||||
{
|
||||
throw new Microsoft.AnalysisServices.ConnectionException($"Could not connect to database {_partitionedModel.AnalysisServicesDatabase}.");
|
||||
}
|
||||
}
|
||||
|
||||
private static List<string> GetPartitionKeys(bool forProcessing, PartitionedTableConfig partitionedTable, Granularity granularity)
|
||||
{
|
||||
//forProcessing: false to return complete target set of partitions, true to return partitons to be processed (may be less if incremental mode).
|
||||
|
||||
List<string> partitionKeys = new List<string>();
|
||||
int numberOfPartitions = (forProcessing && !_partitionedModel.InitialSetUp ? partitionedTable.NumberOfPartitionsForIncrementalProcess : partitionedTable.NumberOfPartitionsFull);
|
||||
|
||||
for (int i = numberOfPartitions - 1; i >= 0; i--)
|
||||
{
|
||||
DateTime periodToAdd;
|
||||
switch (granularity)
|
||||
{
|
||||
case Granularity.Daily:
|
||||
periodToAdd = partitionedTable.MaxDate.AddDays(-i);
|
||||
partitionKeys.Add(Convert.ToString((periodToAdd.Year * 100 + periodToAdd.Month) * 100 + periodToAdd.Day));
|
||||
break;
|
||||
case Granularity.Monthly:
|
||||
periodToAdd = partitionedTable.MaxDate.AddMonths(-i);
|
||||
partitionKeys.Add(Convert.ToString(periodToAdd.Year * 100 + periodToAdd.Month));
|
||||
break;
|
||||
default: //Granularity.Yearly:
|
||||
periodToAdd = partitionedTable.MaxDate.AddYears(-i);
|
||||
partitionKeys.Add(Convert.ToString(periodToAdd.Year));
|
||||
break;
|
||||
}
|
||||
}
|
||||
partitionKeys.Sort();
|
||||
|
||||
return partitionKeys;
|
||||
}
|
||||
|
||||
private static List<string> GetPartitionKeysTable(Table table, Granularity granularity)
|
||||
{
|
||||
List<string> partitionKeysExisting = new List<string>();
|
||||
|
||||
foreach (Partition partition in table.Partitions)
|
||||
{
|
||||
//Ignore partitions that don't follow the convention yyyy, yyyymm or yyyymmdd
|
||||
int partitionKey;
|
||||
if (
|
||||
( ( partition.Name.Length == 4 && granularity == Granularity.Yearly ) ||
|
||||
( partition.Name.Length == 6 && granularity == Granularity.Monthly ) ||
|
||||
( partition.Name.Length == 8 && granularity == Granularity.Daily )
|
||||
) && int.TryParse(partition.Name, out partitionKey)
|
||||
)
|
||||
{
|
||||
partitionKeysExisting.Add(Convert.ToString(partitionKey));
|
||||
}
|
||||
}
|
||||
partitionKeysExisting.Sort();
|
||||
|
||||
return partitionKeysExisting;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AsPartitionProcessing
|
||||
{
|
||||
/// <summary>
|
||||
/// Configuration information for a partitioned AS tabular model.
|
||||
/// </summary>
|
||||
public class PartitionedModelConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// ID of the PartitionedModelConfig table.
|
||||
/// </summary>
|
||||
public int PartitionedModelConfigID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Analysis Services instance. Can be SSAS or an Azure AS URL.
|
||||
/// </summary>
|
||||
public string AnalysisServicesServer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Analysis Services database.
|
||||
/// </summary>
|
||||
public string AnalysisServicesDatabase { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True for initial set up to create partitions and process them sequentially. False for incremental processing.
|
||||
/// </summary>
|
||||
public bool InitialSetUp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When initialSetUp=false, determines if processing is performed as an online operation, which may require more memory, but users can still query the model.
|
||||
/// </summary>
|
||||
public bool IncrementalOnline { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When initialSetUp=false, determines if separate tables are processed in parallel. Partitions within a table are always processed in parallel.
|
||||
/// </summary>
|
||||
public bool IncrementalParallelTables { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Should always set to true for SSAS implementations that will run under the current process account. For Azure AS, normally set to false.
|
||||
/// </summary>
|
||||
public bool IntegratedAuth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Only applies when integratedAuth=false. Used for Azure AD UPNs to connect to Azure AS.
|
||||
/// </summary>
|
||||
public string UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Only applies when integratedAuth=false. Used for Azure AD UPNs to connect to Azure AS.
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Collection of partitioned tables containing configuration information.
|
||||
/// </summary>
|
||||
public List<PartitionedTableConfig> PartitionedTables { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Connection information to connect to the configuration and logging database.
|
||||
/// </summary>
|
||||
public ConfigDatabaseConnectionInfo ConfigDatabaseConnectionInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// GUID generated to the execution run.
|
||||
/// </summary>
|
||||
public string ExecutionID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Parameters normally from configuration database to determine partitioning ranges and design.
|
||||
/// </summary>
|
||||
/// <param name="partitionedModelConfigID">ID of the PartitionedModelConfig table.</param>
|
||||
/// <param name="analysisServicesServer">Name of the Analysis Services instance. Can be SSAS or an Azure AS URL.</param>
|
||||
/// <param name="analysisServicesDatabase">Name of the Analysis Services database.</param>
|
||||
/// <param name="initialSetUp">True for initial set up to create partitions and process them sequentially. False for incremental processing.</param>
|
||||
/// <param name="incrementalOnline">When initialSetUp=false, determines if processing is performed as an online operation, which may require more memory, but users can still query the model.</param>
|
||||
/// <param name="incrementalParallelTables">When initialSetUp=false, determines if separate tables are processed in parallel. Partitions within a table are always processed in parallel.</param>
|
||||
/// <param name="integratedAuth">Should always set to true for SSAS implementations that will run under the current process account. For Azure AS, normally set to false.</param>
|
||||
/// <param name="userName">Only applies when integratedAuth=false. Used for Azure AD UPNs to connect to Azure AS.</param>
|
||||
/// <param name="password">Only applies when integratedAuth=false. Used for Azure AD UPNs to connect to Azure AS.</param>
|
||||
/// <param name="partitionedTables">Collection of partitioned tables containing configuration information.</param>
|
||||
public PartitionedModelConfig(
|
||||
int partitionedModelConfigID,
|
||||
string analysisServicesServer,
|
||||
string analysisServicesDatabase,
|
||||
bool initialSetUp,
|
||||
bool incrementalOnline,
|
||||
bool incrementalParallelTables,
|
||||
bool integratedAuth,
|
||||
string userName,
|
||||
string password,
|
||||
List<PartitionedTableConfig> partitionedTables
|
||||
)
|
||||
{
|
||||
PartitionedModelConfigID = partitionedModelConfigID;
|
||||
AnalysisServicesServer = analysisServicesServer;
|
||||
AnalysisServicesDatabase = analysisServicesDatabase;
|
||||
InitialSetUp = initialSetUp;
|
||||
IncrementalOnline = incrementalOnline;
|
||||
IncrementalParallelTables = incrementalParallelTables;
|
||||
IntegratedAuth = integratedAuth;
|
||||
UserName = userName;
|
||||
Password = password;
|
||||
PartitionedTables = partitionedTables;
|
||||
ExecutionID = Guid.NewGuid().ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor.
|
||||
/// </summary>
|
||||
public PartitionedModelConfig()
|
||||
{
|
||||
ExecutionID = Guid.NewGuid().ToString();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
using System;
|
||||
|
||||
namespace AsPartitionProcessing
|
||||
{
|
||||
/// <summary>
|
||||
/// Configuration information for a partitioned table within an AS tabular model.
|
||||
/// </summary>
|
||||
public class PartitionedTableConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// ID of the PartitionedTableConfig table.
|
||||
/// </summary>
|
||||
public int PartitionedTableConfigID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The maximum date that needs to be accounted for in the partitioned table. Represents the upper boundary of the rolling window.
|
||||
/// </summary>
|
||||
public DateTime MaxDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Partition granularity, which can be Yearly, Monthly or Daily.
|
||||
/// </summary>
|
||||
public Granularity Granularity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Count of all partitions in the rolling window. For example, a rolling window of 10 years partitioned by month would result in 120 partitions.
|
||||
/// </summary>
|
||||
public int NumberOfPartitionsFull { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Count of “hot partitions” where the data can change. For example, it may be necessary to refresh the most recent 3 months of data every day. This only applies to the most recent partitions.
|
||||
/// </summary>
|
||||
public int NumberOfPartitionsForIncrementalProcess { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the partitioned table in the tabular model.
|
||||
/// </summary>
|
||||
public string AnalysisServicesTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the source table in the relational database.
|
||||
/// </summary>
|
||||
public string SourceTableName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the source column from the table in the relational database.
|
||||
/// </summary>
|
||||
public string SourcePartitionColumn { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize configuration info for partitioned table. Normally populated from a configuration database.
|
||||
/// </summary>
|
||||
/// <param name="model">Parent model.</param>
|
||||
/// <param name="partitionedTableConfigID">ID of the PartitionedTableConfig table.</param>
|
||||
/// <param name="maxDate">The maximum date that needs to be accounted for in the partitioned table. Represents the upper boundary of the rolling window.</param>
|
||||
/// <param name="granularity">Partition granularity, which can be Yearly, Monthly or Daily.</param>
|
||||
/// <param name="numberOfPartitionsFull">Count of all partitions in the rolling window. For example, a rolling window of 10 years partitioned by month would result in 120 partitions.</param>
|
||||
/// <param name="numberOfPartitionsForIncrementalProcess">Count of “hot partitions” where the data can change. For example, it may be necessary to refresh the most recent 3 months of data every day. This only applies to the most recent partitions.</param>
|
||||
/// <param name="analysisServicesTable">Name of the partitioned table in the tabular model.</param>
|
||||
/// <param name="sourceTableName">Name of the source table in the relational database.</param>
|
||||
/// <param name="sourcePartitionColumn">Name of the source column from the table in the relational database.</param>
|
||||
public PartitionedTableConfig(
|
||||
int partitionedTableConfigID,
|
||||
DateTime maxDate,
|
||||
Granularity granularity,
|
||||
int numberOfPartitionsFull,
|
||||
int numberOfPartitionsForIncrementalProcess,
|
||||
string analysisServicesTable,
|
||||
string sourceTableName,
|
||||
string sourcePartitionColumn
|
||||
)
|
||||
{
|
||||
PartitionedTableConfigID = partitionedTableConfigID;
|
||||
MaxDate = maxDate;
|
||||
Granularity = granularity;
|
||||
NumberOfPartitionsFull = numberOfPartitionsFull;
|
||||
NumberOfPartitionsForIncrementalProcess = numberOfPartitionsForIncrementalProcess;
|
||||
AnalysisServicesTable = analysisServicesTable;
|
||||
SourceTableName = sourceTableName;
|
||||
SourcePartitionColumn = sourcePartitionColumn;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumeration of supported partition granularities.
|
||||
/// </summary>
|
||||
public enum Granularity
|
||||
{
|
||||
Daily = 0,
|
||||
Monthly = 1,
|
||||
Yearly = 2
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("AsPartitionProcessing")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft Corporation")]
|
||||
[assembly: AssemblyProduct("AsPartitionProcessing")]
|
||||
[assembly: AssemblyCopyright("Copyright © Microsoft Corporation 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("fb937281-b06d-47fb-9846-e97b0287afce")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
87
AsPartitionProcessing/CreateDatabaseObjects.sql
Normal file
87
AsPartitionProcessing/CreateDatabaseObjects.sql
Normal file
@ -0,0 +1,87 @@
|
||||
CREATE DATABASE [AsPartitionProcessing]
|
||||
GO
|
||||
USE [AsPartitionProcessing]
|
||||
GO
|
||||
|
||||
CREATE TABLE [dbo].[PartitionedModelConfig](
|
||||
[PartitionedModelConfigID] [int] NOT NULL,
|
||||
[AnalysisServicesServer] [varchar](255) NOT NULL,
|
||||
[AnalysisServicesDatabase] [varchar](255) NOT NULL,
|
||||
[InitialSetUp] [bit] NOT NULL,
|
||||
[IncrementalOnline] [bit] NOT NULL,
|
||||
[IncrementalParallelTables] [bit] NOT NULL,
|
||||
[IntegratedAuth] [bit] NOT NULL,
|
||||
CONSTRAINT [PK_PartitionedDatabaseConfig] PRIMARY KEY CLUSTERED
|
||||
(
|
||||
[PartitionedModelConfigID] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
GO
|
||||
|
||||
CREATE TABLE [dbo].[PartitionedTableConfig](
|
||||
[PartitionedTableConfigID] [int] NOT NULL,
|
||||
[PartitionedModelConfigID] [int] NOT NULL,
|
||||
[MaxDate] [date] NOT NULL,
|
||||
[Granularity] [tinyint] NOT NULL,
|
||||
[NumberOfPartitionsFull] [int] NOT NULL,
|
||||
[NumberOfPartitionsForIncrementalProcess] [int] NOT NULL,
|
||||
[AnalysisServicesTable] [varchar](255) NOT NULL,
|
||||
[SourceTableName] [varchar](255) NOT NULL,
|
||||
[SourcePartitionColumn] [varchar](255) NOT NULL,
|
||||
CONSTRAINT [PK_PartitionedTablesConfig] PRIMARY KEY CLUSTERED
|
||||
(
|
||||
[PartitionedTableConfigID] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
GO
|
||||
|
||||
CREATE TABLE [dbo].[PartitionedModelLog](
|
||||
[PartitionedModelLogID] [int] IDENTITY(1,1) NOT NULL,
|
||||
[PartitionedModelConfigID] [int] NOT NULL,
|
||||
[ExecutionID] [char](36) NOT NULL,
|
||||
[LogDateTime] [datetime] NOT NULL,
|
||||
[Message] [varchar](8000) NOT NULL,
|
||||
CONSTRAINT [PK_PartitionedModelLog] PRIMARY KEY CLUSTERED
|
||||
(
|
||||
[PartitionedModelLogID] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
GO
|
||||
|
||||
ALTER TABLE [dbo].[PartitionedTableConfig] WITH CHECK ADD CONSTRAINT [FK_PartitionedTableConfig_PartitionedDatabaseConfig] FOREIGN KEY([PartitionedModelConfigID])
|
||||
REFERENCES [dbo].[PartitionedModelConfig] ([PartitionedModelConfigID])
|
||||
GO
|
||||
|
||||
ALTER TABLE [dbo].[PartitionedTableConfig] CHECK CONSTRAINT [FK_PartitionedTableConfig_PartitionedDatabaseConfig]
|
||||
GO
|
||||
|
||||
ALTER TABLE [dbo].[PartitionedModelLog] WITH CHECK ADD CONSTRAINT [FK_PartitionedModelLog_PartitionedModelConfig] FOREIGN KEY([PartitionedModelConfigID])
|
||||
REFERENCES [dbo].[PartitionedModelConfig] ([PartitionedModelConfigID])
|
||||
GO
|
||||
|
||||
ALTER TABLE [dbo].[PartitionedModelLog] CHECK CONSTRAINT [FK_PartitionedModelLog_PartitionedModelConfig]
|
||||
GO
|
||||
|
||||
|
||||
|
||||
CREATE VIEW [dbo].[vPartitionedTableConfig]
|
||||
AS
|
||||
SELECT m.[PartitionedModelConfigID]
|
||||
,m.[AnalysisServicesServer]
|
||||
,m.[AnalysisServicesDatabase]
|
||||
,m.[InitialSetUp]
|
||||
,m.[IncrementalOnline]
|
||||
,m.[IncrementalParallelTables]
|
||||
,m.[IntegratedAuth]
|
||||
,t.[PartitionedTableConfigID]
|
||||
,t.[MaxDate]
|
||||
,t.[Granularity]
|
||||
,t.[NumberOfPartitionsFull]
|
||||
,t.[NumberOfPartitionsForIncrementalProcess]
|
||||
,t.[AnalysisServicesTable]
|
||||
,t.[SourceTableName]
|
||||
,t.[SourcePartitionColumn]
|
||||
FROM [dbo].[PartitionedTableConfig] t
|
||||
INNER JOIN [dbo].[PartitionedModelConfig] m ON t.[PartitionedModelConfigID] = m.[PartitionedModelConfigID]
|
||||
GO
|
||||
|
34
AsPartitionProcessing/SampleConfiguration.sql
Normal file
34
AsPartitionProcessing/SampleConfiguration.sql
Normal file
@ -0,0 +1,34 @@
|
||||
INSERT INTO [dbo].[PartitionedModelConfig]
|
||||
VALUES(
|
||||
1 --[PartitionedModelConfigID]
|
||||
,'localhost' --[AnalysisServicesServer]
|
||||
,'AdventureWorks' --[AnalysisServicesDatabase]
|
||||
,1 --[InitialSetUp]
|
||||
,1 --[IncrementalOnline]
|
||||
,1 --[IncrementalParallelTables]
|
||||
,1 --[IntegratedAuth]
|
||||
);
|
||||
|
||||
INSERT INTO [dbo].[PartitionedTableConfig]
|
||||
VALUES(
|
||||
1 --[PartitionedTableConfigID]
|
||||
,1 --[PartitionedModelConfigID]
|
||||
,'2012-12-01' --[MaxDate]
|
||||
,1 --[Granularity] 1=Monthly
|
||||
,12 --[NumberOfPartitionsFull]
|
||||
,3 --[NumberOfPartitionsForIncrementalProcess]
|
||||
,'Internet Sales' --[AnalysisServicesTable]
|
||||
,'[dbo].[FactInternetSales]'--[SourceTableName]
|
||||
,'OrderDateKey' --[SourcePartitionColumn]
|
||||
),
|
||||
(
|
||||
2 --[PartitionedTableConfigID]
|
||||
,1 --[PartitionedModelConfigID]
|
||||
,'2012-12-01' --[MaxDate]
|
||||
,2 --[Granularity] 2=Yearly
|
||||
,3 --[NumberOfPartitionsFull]
|
||||
,1 --[NumberOfPartitionsForIncrementalProcess]
|
||||
,'Reseller Sales' --[AnalysisServicesTable]
|
||||
,'[dbo].[FactResellerSales]'--[SourceTableName]
|
||||
,'OrderDateKey' --[SourcePartitionColumn]
|
||||
);
|
Loading…
Reference in New Issue
Block a user