大規模なサードパーティのデータセットを使用しています。長い経験から、システムに入力したらすぐにデータの着信行にサロゲートIDを付与して、検証や保管などの際に簡単に追跡できるようにすることは非常に良いアイデアであることがわかりました。問題は、キー値が潜在的にすべてのディメンション値であり、200列にすることができます。
私の一般的なプロセスはこれです:
キー値と代理IDSのみを保持する2番目のIdMatchテーブルとデータを照合します。
IF OBJECT_ID('Staging.myTest') IS NULL
CREATE TABLE Staging.myTest (
[ID] INT IDENTITY(1,1) NOT NULL,
[Hash] INT NULL,
[Dim_1] NVARCHAR(32) NOT NULL,
[Dim_2] NVARCHAR(32) NOT NULL,
[Dim_3] NVARCHAR(32) NULL,
[Met_1] INT NULL,
[Met_2] DECIMAL(5,2) NULL
);
IF OBJECT_ID('IdMatch.myTest') IS NULL
CREATE TABLE IdMatch.myTest (
[ID] INT IDENTITY(1,1) NOT NULL,
[Hash] INT NULL,
[Dim_1] NVARCHAR(32) NOT NULL,
[Dim_2] NVARCHAR(32) NOT NULL,
[Dim_3] NVARCHAR(32) NULL,
);
TRUNCATE TABLE Staging.myTest;
TRUNCATE TABLE IdMatch.myTest;
INSERT INTO Staging.myTest
([Dim_1], [Dim_2], [Dim_3])
VALUES ('A', 'A', 'A'),
('B', 'B', 'B'),
('C', 'C', NULL),
('C', 'C', 'C'),
('D', 'D', 'D');
INSERT INTO IdMatch.myTest
([Dim_1], [Dim_2], [Dim_3])
VALUES ('A', 'A', 'A');
--My Proc (as script) for setting the index.
INSERT INTO [IdMatch].myTest
([Dim_1], [Dim_2], [Dim_3])
SELECT src.[Dim_1], src.[Dim_2], src.[Dim_3]
FROM Staging.myTest AS src
WHERE NOT EXISTS (
SELECT tgt.[Dim_1], tgt.[Dim_2], tgt.[Dim_3]
FROM [IdMatch].myTest AS tgt
WHERE tgt.[Dim_1] = src.[Dim_1]
AND tgt.[Dim_2] = src.[Dim_2]
AND tgt.[Dim_3] = src.[Dim_3]
);
SELECT * FROM IdMatch.myTest
問題:この方法でサロゲートIDを取得するためのマッチングは、実際のデータセットにNVARCHARデータの200以上の列が含まれている場合、長い時間がかかります。もっと良い方法はありますか?私は事前計算ハッシュを試しましたが、私が生成する最終的な衝突を処理する方法がわかりません。
一般的なアプローチの1つは、衝突の可能性が非常に低いハッシュ関数を選択して、存在しないと想定することです。
CREATE TABLE Staging.myTest (
[ID] INT IDENTITY(1,1) NOT NULL,
[Hash] AS
CONVERT(binary(32),
HASHBYTES('SHA2_256',
CONCAT(Dim_1, N'|', Dim_2, N'|', Dim_3))),
[Dim_1] NVARCHAR(32) NOT NULL,
[Dim_2] NVARCHAR(32) NOT NULL,
[Dim_3] NVARCHAR(32) NULL,
[Met_1] INT NULL,
[Met_2] DECIMAL(5,2) NULL
);
GO
CREATE TABLE IdMatch.myTest (
[ID] INT IDENTITY(1,1) NOT NULL,
[Hash] AS
CONVERT(binary(32),
HASHBYTES('SHA2_256',
CONCAT(Dim_1, N'|', Dim_2, N'|', Dim_3))),
[Dim_1] NVARCHAR(32) NOT NULL,
[Dim_2] NVARCHAR(32) NOT NULL,
[Dim_3] NVARCHAR(32) NULL,
);
GO
-- Declared unique because we have decided it will be
CREATE UNIQUE NONCLUSTERED INDEX
IX_HASH
ON IdMatch.myTest
([Hash]);
注:ほとんどの人は、ハッシュのために列のNULLを空の文字列に置き換えます。これは、CONCAT
のデフォルトの動作です。 NULLと空の文字列を区別する必要がある場合は、使用する他のマジック値を特定し、null許容列をISNULL
またはCOALESCE
でラップする必要があります。
次に、一致しない行を追加します。
INSERT Staging.myTest
(
Dim_1,
Dim_2,
Dim_3
)
SELECT
SRC.Dim_1,
SRC.Dim_2,
SRC.Dim_3
FROM Staging.myTest AS SRC
WHERE
NOT EXISTS
(
SELECT 1
FROM IdMatch.myTest AS TGT
WHERE
TGT.[Hash] = SRC.[Hash]
);
Greg Lowによる T-SQLで変更された行の検索– CHECKSUM、BINARY_CHECKSUM、HASHBYTES を参照してください。この方法をデータでテストして、このスキームが機能するかどうかを確認する必要があります。
あなたの 前の質問 はハッシュとしてCHECKSUM
を使用して言及されました。私の他の回答で述べたように、これは一般に機能しませんが、試してみたい場合、可能な実装は以下のとおりです。
CREATE TABLE Staging.myTest (
[ID] INT IDENTITY(1,1) NOT NULL,
[Hash] AS CHECKSUM(Dim_1, Dim_2, Dim_3),
[Dim_1] NVARCHAR(32) NOT NULL,
[Dim_2] NVARCHAR(32) NOT NULL,
[Dim_3] NVARCHAR(32) NULL,
[Met_1] INT NULL,
[Met_2] DECIMAL(5,2) NULL
);
GO
CREATE TABLE IdMatch.myTest (
[ID] INT IDENTITY(1,1) NOT NULL,
[Hash] AS CHECKSUM(Dim_1, Dim_2, Dim_3),
[Dim_1] NVARCHAR(32) NOT NULL,
[Dim_2] NVARCHAR(32) NOT NULL,
[Dim_3] NVARCHAR(32) NULL,
);
GO
-- For lookups
CREATE UNIQUE CLUSTERED INDEX c ON IdMatch.myTest (ID);
GO
-- Not unique!
CREATE NONCLUSTERED INDEX
IX_HASH
ON IdMatch.myTest
([Hash]);
新しい行を見つけるには、ハッシュの衝突も考慮する必要があります。ここでの考え方は、ハッシュチェックが一致の可能性を見つけた場合にのみ、列を詳細にチェックすることです。
INSERT Staging.myTest
(
Dim_1,
Dim_2,
Dim_3
)
SELECT
SRC.Dim_1,
SRC.Dim_2,
SRC.Dim_3
FROM Staging.myTest AS SRC
LEFT JOIN IdMatch.myTest AS HSH
ON HSH.[Hash] = SRC.[Hash]
WHERE
1 = CASE
-- No hash match, definitely missing (pass through)
WHEN HSH.[Hash] IS NULL THEN 1
-- Hash match, check columns in detail to confirm
WHEN NOT EXISTS
(
-- Null-aware column comparison
SELECT
-- Source column list
SRC.Dim_1, SRC.Dim_2, SRC.Dim_3
INTERSECT
SELECT
-- Target column list
T.Dim_1, T.Dim_2, T.Dim_3
FROM IdMatch.myTest AS T
WHERE
T.ID = HSH.ID
) THEN 1
-- Otherwise exact match already exists
ELSE 0
END;
Null対応の列比較は、私の記事 非文書化クエリプラン:等価比較 で説明されています。
このクエリを正しく記述し、完全な列比較の前にハッシュチェックを保証する方法はいくつかあります。これはCASE
を使用して記述したものです。これにより、ロジックが非常に明確になり、実行プランの形が気に入ったからです。