내 작업의 일부는 짜증 해시 알고리즘 을 구현 하는 CLR 함수를 사용하여 행을 비교하여 열 값이 변경되었는지 확인합니다. CLR 함수는 이진 문자열을 입력으로 사용하므로 행을 이진 문자열로 변환하는 빠른 방법이 필요합니다. 전체 워크로드 중에 약 100 억 행을 해시 할 것으로 예상되므로이 코드를 최대한 빨리 처리하고 싶습니다.
다른 스키마를 가진 약 300 개의 테이블이 있습니다. 이 질문의 목적 상 32 개의 널 입력 가능 INT
열로 구성된 간단한 테이블 구조를 가정하십시오 . 이 질문의 맨 아래에 결과를 벤치마킹하는 방법과 샘플 데이터를 제공했습니다.
모든 열 값이 동일한 경우 행을 동일한 이진 문자열로 변환해야합니다. 열 값이 다른 경우 행을 다른 이진 문자열로 변환해야합니다. 예를 들어 다음과 같은 간단한 코드는 작동하지 않습니다.
CAST(COL1 AS BINARY(4)) + CAST(COL2 AS BINARY(4)) + ..
NULL을 올바르게 처리하지 않습니다. COL1
행 1의 경우 COL2
NULL이고 행 2의 경우 NULL이면 두 행이 모두 NULL 문자열로 변환됩니다. NULL을 올바르게 처리하는 것이 전체 행을 올바르게 변환하는 데 가장 어려운 부분이라고 생각합니다. INT 열에 허용되는 모든 값이 가능합니다.
몇 가지 질문을 선점하려면 :
- 중요한 경우, 열의 대부분 (90 % 이상)은 열이 NULL이 아닙니다.
- CLR을 사용해야합니다.
- 이 많은 행을 해시해야합니다. 해시를 유지할 수 없습니다.
- CLR 기능이 있기 때문에 변환에 배치 모드를 사용할 수 없다고 생각합니다.
널 입력 가능 INT
열을 32 개 BINARY(X)
또는 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;
(이 바이너리 결과에는 여전히 으스스한 해시를 사용합니다. 워크로드는 해시 조인을 사용하고 해시 값은 해시 빌드 중 하나에 사용됩니다. 해시 빌드에는 긴 바이너리 값이 필요하지 않습니다. 기억.)