ワークロードの一部では、不気味なハッシュアルゴリズムを実装するCLR関数を使用して行を比較し、列の値が変更されたかどうかを確認します。CLR関数はバイナリ文字列を入力として受け取るため、行をバイナリ文字列に変換する高速な方法が必要です。全ワークロード中に約100億行をハッシュすると予想されるため、このコードを可能な限り高速にしたいと思います。
異なるスキーマを持つ約300のテーブルがあります。この質問の目的のために、32のNULL入力可能INT
列の単純なテーブル構造を想定してください。サンプルデータと、この質問の最後に結果をベンチマークする方法を提供しました。
すべての列の値が同じ場合、行は同じバイナリ文字列に変換する必要があります。列の値が異なる場合、行は異なるバイナリ文字列に変換する必要があります。たとえば、次のような単純なコードは機能しません。
CAST(COL1 AS BINARY(4)) + CAST(COL2 AS BINARY(4)) + ..
NULLを正しく処理しません。場合COL1
NULLが行1のためのものであり、COL2
行2のためにNULLである、両方の行がNULL文字列に変換されます。NULLを正しく処理することは、行全体を正しく変換することの最も難しい部分だと思います。INT列に許可されるすべての値が可能です。
質問を先取りするには:
- それが重要な場合、ほとんどの時間(90%+)の列はNULLになりません。
- CLRを使用する必要があります。
- この数の行をハッシュする必要があります。ハッシュを維持できません。
- CLR関数があるため、変換にバッチモードを使用できないと思います。
32個のNULL可能INT
列をBINARY(X)
or VARBINARY(X)
文字列に変換する最速の方法は何ですか?
約束どおりのサンプルデータとコード:
-- create sample data
DROP TABLE IF EXISTS dbo.TABLE_OF_32_INTS;
CREATE TABLE dbo.TABLE_OF_32_INTS (
COL1 INT NULL,
COL2 INT NULL,
COL3 INT NULL,
COL4 INT NULL,
COL5 INT NULL,
COL6 INT NULL,
COL7 INT NULL,
COL8 INT NULL,
COL9 INT NULL,
COL10 INT NULL,
COL11 INT NULL,
COL12 INT NULL,
COL13 INT NULL,
COL14 INT NULL,
COL15 INT NULL,
COL16 INT NULL,
COL17 INT NULL,
COL18 INT NULL,
COL19 INT NULL,
COL20 INT NULL,
COL21 INT NULL,
COL22 INT NULL,
COL23 INT NULL,
COL24 INT NULL,
COL25 INT NULL,
COL26 INT NULL,
COL27 INT NULL,
COL28 INT NULL,
COL29 INT NULL,
COL30 INT NULL,
COL31 INT NULL,
COL32 INT NULL
);
INSERT INTO dbo.TABLE_OF_32_INTS WITH (TABLOCK)
SELECT 0, 123, 12345, 1234567, 123456789
, 0, 123, 12345, 1234567, 123456789
, 0, 123, 12345, 1234567, 123456789
, 0, 123, 12345, 1234567, 123456789
, 0, 123, 12345, 1234567, 123456789
, 0, 123, 12345, 1234567, 123456789
, NULL, -876545321
FROM
(
SELECT TOP (1000000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
) q
OPTION (MAXDOP 1);
GO
-- procedure to test performance
CREATE OR ALTER PROCEDURE #p AS
BEGIN
SET NOCOUNT ON;
DECLARE
@counter INT = 0,
@dummy VARBINARY(8000);
WHILE @counter < 10
BEGIN
SELECT @dummy = -- this code is clearly incomplete as it does not handle NULLs
CAST(COL1 AS BINARY(4)) +
CAST(COL2 AS BINARY(4)) +
CAST(COL3 AS BINARY(4)) +
CAST(COL4 AS BINARY(4)) +
CAST(COL5 AS BINARY(4)) +
CAST(COL6 AS BINARY(4)) +
CAST(COL7 AS BINARY(4)) +
CAST(COL8 AS BINARY(4)) +
CAST(COL9 AS BINARY(4)) +
CAST(COL10 AS BINARY(4)) +
CAST(COL11 AS BINARY(4)) +
CAST(COL12 AS BINARY(4)) +
CAST(COL13 AS BINARY(4)) +
CAST(COL14 AS BINARY(4)) +
CAST(COL15 AS BINARY(4)) +
CAST(COL16 AS BINARY(4)) +
CAST(COL17 AS BINARY(4)) +
CAST(COL18 AS BINARY(4)) +
CAST(COL19 AS BINARY(4)) +
CAST(COL20 AS BINARY(4)) +
CAST(COL21 AS BINARY(4)) +
CAST(COL22 AS BINARY(4)) +
CAST(COL23 AS BINARY(4)) +
CAST(COL24 AS BINARY(4)) +
CAST(COL25 AS BINARY(4)) +
CAST(COL26 AS BINARY(4)) +
CAST(COL27 AS BINARY(4)) +
CAST(COL28 AS BINARY(4)) +
CAST(COL29 AS BINARY(4)) +
CAST(COL30 AS BINARY(4)) +
CAST(COL31 AS BINARY(4)) +
CAST(COL32 AS BINARY(4))
FROM dbo.TABLE_OF_32_INTS
OPTION (MAXDOP 1);
SET @counter = @counter + 1;
END;
SELECT cpu_time
FROM sys.dm_exec_requests
WHERE session_id = @@SPID;
END;
GO
-- run procedure
EXEC #p;
(このバイナリ結果で不気味なハッシュを使用します。ワークロードはハッシュ結合を使用し、ハッシュ値はハッシュビルドの1つに使用されます。メモリ。)