PCDimNaturalizer (Mosha Pasumansky さんのブログから)

Mosha Pasumansky さんのブログ投稿のご紹介です。(翻訳の許可を頂いています。翻訳の正確さは保証できません。)

原文:http://sqlblog.com/blogs/mosha/archive/2008/08/25/parent-child-dimension-table-naturalizer.aspx

                                                                                                                                                          • -

「Parent-Child Dimension Table Naturalizer」

親子ディメンションは Analysis Services の重要な機能の 1 つです。親子ディメンションは BOM(部品表)、勘定科目一覧表、組織図などのようなシナリオに関するディメンションモデリングを行う際に柔軟性を与えます。しかし、この柔軟性はコストを伴います。親子ディメンションの使いすぎはパフォーマンスの問題を引き起こしますし、さらに、そこには計算における問題を引き起こす意味的な*ねじれ*があります。例えば親子ディメンションは、(ノーマルなディメンションがそうするように)関係属性を解析しません。ですから、場合によっては親子階層をノーマルなマルチレベル階層に変換することが望ましいこともあります。この変換のプロセスは些細なものではなく、いくつかのステップを含んでいます。

マイクロソフト社の? Senior Support Escalation Engineer である Jon Burchel 氏 はこの問題を深く調べて、"Analysis Services Dimension Table Naturalizer" または "PCDimNaturalizer" と呼ばれる、親子ディメンションを通常のディメンションに自動的に変換するツールを考え出しました。彼は www.codeplex.com にそのプロジェクトを置きました。これは、すべてのソースコードを入手可能であることを意味します。このツールは、ほとんどの(少なくとも codeplex の)オープンソースプロジェクトとは異なり、しっかりとドキュメント化されています。(私は、Support Engineer である Jon が、良く出来たドキュメントの価値を本当に理解していると考えています。)PCDimNaturalizer はコマンドラインまたは UI から使用できます。また、.NET アプリケーション や SSIS パッケージに組み込むためのオブジェクトモデルを公開しています。

私はこのツールが、多くの Analysis Services を実践している方々にとって役に立つことを確信しています。
codeplex の PCDimNaturalizer プロジェクトはこちら: http://www.codeplex.com/PCDimNaturalize

                                                                                                                                                          • -

というわけで、PCDimNaturalizer を使ってみました。

1. 親子ディメンションを設定
 AdventureWorksDW データベース の DimEmployee テーブルを対象にして、
 ・Employee Key を Usage : Key
 ・ParentEmployeeKey を Usage : Parent
 おまけとして
 ・Last Name を Usage : Regular
 としてディメンションを設定しました。

2. 配置 + ビルド
 Analysis Services インスタンスに配置してビルドします。

3. PCDimNaturalizer で、対象ディメンションとして指定
 PCDimNaturalizer を起動し、対象のインスタンス、データベース、ディメンションを指定します。

4. PCDimNaturalizer のオプションを指定して、実行します。
 主なオプション
 ○"Action Level for naturalization"
   Level 1 : Create SQL View
   Level 2 : Add to data source view
   Level 3 : Create naturalized dimension
   Level 4 : Add to cube(s)
   Level 5 : Process
  ※「データソースにビューを作り」→「"データソースビュー"に加え」→「ディメンションを設定し」→「キューブに加え」→「処理する」という
   ステップのうちのどこまでやるかの指定です。
 ○"Minimam levels"
  自動的に階層数を調べて、「Level 1 : Create SQL View」で作るビューでの階層数を決めるようですが、これの指定により
  実データに存在しない数の階層を作るようです。

5. 結果
 「Level 1 : Create SQL View」でのみ、動作しました。
 「Level 2 : Add to data source view」より上位の設定では正しく動作しませんでした。データソースビューの作成がエラーになってしまいました。
 作成されたビューを載せてておきます。このビューがキモですので、どんな機能なのかはこのビューだけで理解できます。
 ちなみに、"Minimam levels"に 7 を指定してみたところ、[Level 08_KeyColumn] まで含まれるビューが生成されました。

                                                                                                                                                          • -

CREATE VIEW [dbo].[DimNaturalized_DimEmployee] AS
WITH PCStructure(Level, [ParentEmployeeKey], [CurrentMember_KeyColumn], [Level 02_KeyColumn], [Level 03_KeyColumn], [Level 04_KeyColumn], [Level 05_KeyColumn], [Level 06_KeyColumn])
AS (SELECT 3 Level, [ParentEmployeeKey], [EmployeeKey], [EmployeeKey] as [Level 02_KeyColumn],
[EmployeeKey] as [Level 03_KeyColumn],
[EmployeeKey] as [Level 04_KeyColumn],
[EmployeeKey] as [Level 05_KeyColumn],
[EmployeeKey] as [Level 06_KeyColumn]
FROM [dbo].[DimEmployee] WHERE [ParentEmployeeKey] IS NULL OR [ParentEmployeeKey] = [EmployeeKey]
UNION ALL SELECT Level + 1, e.[ParentEmployeeKey], e.[EmployeeKey], CASE Level
WHEN 2 THEN e.[EmployeeKey] ELSE [Level 02_KeyColumn]
END
AS [Level 02_KeyColumn],
CASE Level
WHEN 2 THEN e.[EmployeeKey]
WHEN 3 THEN e.[EmployeeKey] ELSE [Level 03_KeyColumn]
END
AS [Level 03_KeyColumn],
CASE Level
WHEN 2 THEN e.[EmployeeKey]
WHEN 3 THEN e.[EmployeeKey]
WHEN 4 THEN e.[EmployeeKey] ELSE [Level 04_KeyColumn]
END
AS [Level 04_KeyColumn],
CASE Level
WHEN 2 THEN e.[EmployeeKey]
WHEN 3 THEN e.[EmployeeKey]
WHEN 4 THEN e.[EmployeeKey]
WHEN 5 THEN e.[EmployeeKey] ELSE [Level 05_KeyColumn]
END
AS [Level 05_KeyColumn],
CASE Level
WHEN 2 THEN e.[EmployeeKey]
WHEN 3 THEN e.[EmployeeKey]
WHEN 4 THEN e.[EmployeeKey]
WHEN 5 THEN e.[EmployeeKey]
WHEN 6 THEN e.[EmployeeKey] ELSE [Level 06_KeyColumn]
END
AS [Level 06_KeyColumn] FROM [dbo].[DimEmployee] e INNER JOIN PCStructure d ON e.[ParentEmployeeKey] = d.[CurrentMember_KeyColumn] AND e.[ParentEmployeeKey] != e.[EmployeeKey])
select CurrentMemberSubselect.*,
Level2Subselect.*, Level3Subselect.*, Level4Subselect.*, Level5Subselect.*, Level6Subselect.*
from PCStructure a
?left outer join (select [EmployeeKey] [CurrentMember_KeyColumn], [EmployeeKey] [CurrentMember_EmployeeKey],
[ParentEmployeeKey] [CurrentMember_ParentEmployeeKey],
[LastName] [CurrentMember_LastName]
from [dbo].[DimEmployee]) CurrentMemberSubselect on CurrentMemberSubselect.[CurrentMember_KeyColumn] = a.[CurrentMember_KeyColumn] left outer join (select [EmployeeKey] [Level 02_KeyColumn], [LastName] [Level 02_Last Name_KeyColumn]
from [dbo].[DimEmployee]) Level2Subselect on Level2Subselect.[Level 02_KeyColumn] = a.[Level 02_KeyColumn]
left outer join (select [EmployeeKey] [Level 03_KeyColumn], [LastName] [Level 03_Last Name_KeyColumn]
from [dbo].[DimEmployee]) Level3Subselect on Level3Subselect.[Level 03_KeyColumn] = a.[Level 03_KeyColumn]
left outer join (select [EmployeeKey] [Level 04_KeyColumn], [LastName] [Level 04_Last Name_KeyColumn]
from [dbo].[DimEmployee]) Level4Subselect on Level4Subselect.[Level 04_KeyColumn] = a.[Level 04_KeyColumn]
left outer join (select [EmployeeKey] [Level 05_KeyColumn], [LastName] [Level 05_Last Name_KeyColumn]
from [dbo].[DimEmployee]) Level5Subselect on Level5Subselect.[Level 05_KeyColumn] = a.[Level 05_KeyColumn]
left outer join (select [EmployeeKey] [Level 06_KeyColumn], [LastName] [Level 06_Last Name_KeyColumn]
from [dbo].[DimEmployee]) Level6Subselect on Level6Subselect.[Level 06_KeyColumn] = a.[Level 06_KeyColumn]

                                                                                                                                                          • -