SQL Serverオプティマイザーには、冗長結合を削除するロジックが含まれていますが、制限があり、結合はおそらく冗長である必要があります。要約すると、結合には4つの効果があります。
- (結合されたテーブルから)列を追加できます
- 行を追加できます(結合されたテーブルがソース行と複数回一致する場合があります)
- 行を削除できます(結合されたテーブルが一致しない場合があります)
NULL
sを導入できます(RIGHT
またはの場合FULL JOIN
)
冗長な結合を正常に削除するには、クエリ(またはビュー)で4つの可能性すべてを考慮する必要があります。これが正しく行われると、その効果は驚くべきものになる可能性があります。例えば:
USE AdventureWorks2012;
GO
CREATE VIEW dbo.ComplexView
AS
SELECT
pc.ProductCategoryID, pc.Name AS CatName,
ps.ProductSubcategoryID, ps.Name AS SubCatName,
p.ProductID, p.Name AS ProductName,
p.Color, p.ListPrice, p.ReorderPoint,
pm.Name AS ModelName, pm.ModifiedDate
FROM Production.ProductCategory AS pc
FULL JOIN Production.ProductSubcategory AS ps ON
ps.ProductCategoryID = pc.ProductCategoryID
FULL JOIN Production.Product AS p ON
p.ProductSubcategoryID = ps.ProductSubcategoryID
FULL JOIN Production.ProductModel AS pm ON
pm.ProductModelID = p.ProductModelID
オプティマイザーは、次のクエリを正常に簡略化できます。
SELECT
c.ProductID,
c.ProductName
FROM dbo.ComplexView AS c
WHERE
c.ProductName LIKE N'G%';
に:

Rob Farleyは、元のMVP Deep Divesの本でこれらのアイデアについて詳しく書いています。また、SQLBitsでこのトピックについて発表した彼の記録があります。
主な制限は、単純化プロセスに寄与するために外部キーの関係は単一のキーに基づく必要があることです。このようなビューに対するクエリのコンパイル時間は、特に結合の数が増えると非常に長くなる可能性があります。すべてのセマンティクスを正確に取得する100テーブルのビューを作成することは非常に難しい場合があります。おそらく動的SQLを使用して、別の解決策を見つけたいと思います。
とは言うものの、非正規化されたテーブルの特定の品質は、ビューの組み立てが非常に簡単であり、強制された不可能な参照列と、100の物理結合演算子のオーバーヘッドなしでこのソリューションを期待どおりに機能させるための適切な制約のみを必要とすることを意味する場合FOREIGN KEYs
がNULL
ありUNIQUE
ます計画の中で。
例
100ではなく10のテーブルを使用する:
-- Referenced tables
CREATE TABLE dbo.Ref01 (col01 tinyint PRIMARY KEY, item varchar(50) NOT NULL UNIQUE);
CREATE TABLE dbo.Ref02 (col02 tinyint PRIMARY KEY, item varchar(50) NOT NULL UNIQUE);
CREATE TABLE dbo.Ref03 (col03 tinyint PRIMARY KEY, item varchar(50) NOT NULL UNIQUE);
CREATE TABLE dbo.Ref04 (col04 tinyint PRIMARY KEY, item varchar(50) NOT NULL UNIQUE);
CREATE TABLE dbo.Ref05 (col05 tinyint PRIMARY KEY, item varchar(50) NOT NULL UNIQUE);
CREATE TABLE dbo.Ref06 (col06 tinyint PRIMARY KEY, item varchar(50) NOT NULL UNIQUE);
CREATE TABLE dbo.Ref07 (col07 tinyint PRIMARY KEY, item varchar(50) NOT NULL UNIQUE);
CREATE TABLE dbo.Ref08 (col08 tinyint PRIMARY KEY, item varchar(50) NOT NULL UNIQUE);
CREATE TABLE dbo.Ref09 (col09 tinyint PRIMARY KEY, item varchar(50) NOT NULL UNIQUE);
CREATE TABLE dbo.Ref10 (col10 tinyint PRIMARY KEY, item varchar(50) NOT NULL UNIQUE);
親テーブルの定義(ページ圧縮あり):
CREATE TABLE dbo.Normalized
(
pk integer IDENTITY NOT NULL,
col01 tinyint NOT NULL REFERENCES dbo.Ref01,
col02 tinyint NOT NULL REFERENCES dbo.Ref02,
col03 tinyint NOT NULL REFERENCES dbo.Ref03,
col04 tinyint NOT NULL REFERENCES dbo.Ref04,
col05 tinyint NOT NULL REFERENCES dbo.Ref05,
col06 tinyint NOT NULL REFERENCES dbo.Ref06,
col07 tinyint NOT NULL REFERENCES dbo.Ref07,
col08 tinyint NOT NULL REFERENCES dbo.Ref08,
col09 tinyint NOT NULL REFERENCES dbo.Ref09,
col10 tinyint NOT NULL REFERENCES dbo.Ref10,
CONSTRAINT PK_Normalized
PRIMARY KEY CLUSTERED (pk)
WITH (DATA_COMPRESSION = PAGE)
);
景色:
CREATE VIEW dbo.Denormalized
WITH SCHEMABINDING AS
SELECT
item01 = r01.item,
item02 = r02.item,
item03 = r03.item,
item04 = r04.item,
item05 = r05.item,
item06 = r06.item,
item07 = r07.item,
item08 = r08.item,
item09 = r09.item,
item10 = r10.item
FROM dbo.Normalized AS n
JOIN dbo.Ref01 AS r01 ON r01.col01 = n.col01
JOIN dbo.Ref02 AS r02 ON r02.col02 = n.col02
JOIN dbo.Ref03 AS r03 ON r03.col03 = n.col03
JOIN dbo.Ref04 AS r04 ON r04.col04 = n.col04
JOIN dbo.Ref05 AS r05 ON r05.col05 = n.col05
JOIN dbo.Ref06 AS r06 ON r06.col06 = n.col06
JOIN dbo.Ref07 AS r07 ON r07.col07 = n.col07
JOIN dbo.Ref08 AS r08 ON r08.col08 = n.col08
JOIN dbo.Ref09 AS r09 ON r09.col09 = n.col09
JOIN dbo.Ref10 AS r10 ON r10.col10 = n.col10;
統計をハックして、オプティマイザーにテーブルが非常に大きいと思わせるようにします。
UPDATE STATISTICS dbo.Normalized WITH ROWCOUNT = 100000000, PAGECOUNT = 5000000;
ユーザークエリの例:
SELECT
d.item06,
d.item07
FROM dbo.Denormalized AS d
WHERE
d.item08 = 'Banana'
AND d.item01 = 'Green';
この実行プランを提供します。

正規化されたテーブルのスキャンは不良に見えますが、両方のブルームフィルタービットマップがストレージエンジンによるスキャン中に適用されます(したがって、一致できない行はクエリプロセッサまで表示されません)。これは、あなたのケースで許容できるパフォーマンスを提供するのに十分であり、オーバーフローした列を持つ元のテーブルをスキャンするよりも確かに優れています。
ある段階でSQLServer2012 Enterpriseにアップグレードできる場合は、別のオプションがあります。正規化されたテーブルに列ストアインデックスを作成することです。
CREATE NONCLUSTERED COLUMNSTORE INDEX cs
ON dbo.Normalized (col01,col02,col03,col04,col05,col06,col07,col08,col09,col10);
実行計画は次のとおりです。

それはおそらくあなたには悪いように見えますが、列ストレージは並外れた圧縮を提供し、実行プラン全体がバッチモードで実行され、すべての寄与列にフィルターが適用されます。サーバーに十分なスレッドと使用可能なメモリがある場合、この代替手段は実際に飛ぶ可能性があります。
最終的に、この正規化が、テーブルの数と、不十分な実行プランを取得したり、過度のコンパイル時間を必要としたりする可能性を考慮すると、正しいアプローチであるかどうかはわかりません。私はおそらく最初に非正規化されたテーブルのスキーマを修正し(適切なデータ型など)、おそらくデータ圧縮を適用します...通常のもの。
データが本当にスタースキーマに属している場合は、繰り返しデータ要素を別々のテーブルに分割するだけでなく、おそらくより多くの設計作業が必要になります。