한 가지 방법은 값에 #temp 테이블을 사용하고 해시 조인을 허용하기 위해 더미 equijoin 열을 도입하는 것입니다. 예를 들면 다음과 같습니다.
-- Create a #temp table with a dummy column to match the hash join
-- and the actual column you want
CREATE TABLE #values (dummy INT NOT NULL, Col0 CHAR(1) NOT NULL)
INSERT INTO #values (dummy, Col0)
VALUES (0, 'A'),
(0, 'B'),
(0, 'C')
GO
-- A similar query, but with a dummy equijoin condition to allow for a hash join
SELECT v.Col0,
CASE v.Col0
WHEN 'A' THEN cs.DataA
WHEN 'B' THEN cs.DataB
WHEN 'C' THEN cs.DataC
END AS Col1
FROM ColumnstoreTable cs
JOIN #values v
-- Join your dummy column to any numeric column on the columnstore,
-- multiplying that column by 0 to ensure a match to all #values
ON v.dummy = cs.DataA * 0
성능 및 쿼리 계획
이 방법은 다음과 같은 쿼리 계획을 생성하며 해시 일치는 배치 모드에서 수행됩니다.
나는 대체 할 경우 SELECT
로 문을 SUM
의 CASE
콘솔에 모든 행을 스트리밍하고 내가 주위에 거짓말을 한 진정한 100MM 행 columnstore 테이블에 쿼리를 실행하는 것을 방지하기 위해 문, 나는 상당히 좋은 성능이 필요한 300MM를 생성하기 위해 참조 행 :
CPU time = 33803 ms, elapsed time = 4363 ms.
그리고 실제 계획은 해시 조인의 좋은 병렬화를 보여줍니다.
모든 행의 값이 동일한 경우 해시 조인 병렬화에 대한 참고 사항
이 쿼리의 성능은 전체 해시 테이블에 액세스 할 수있는 조인의 프로브쪽에있는 각 스레드에 크게 의존합니다 (해시 분할 버전과는 달리, 하나의 고유 값만있는 경우 모든 행을 단일 스레드에 매핑 함) 위한 dummy
열).
운 좋게도,이 경우 ( Parallelism
프로브 측에 연산자가 없기 때문에) 배치 모드는 스레드간에 공유되는 단일 해시 테이블을 빌드하므로 확실하게 사실이어야합니다. 따라서 각 스레드는에서 행을 가져 와서 Columnstore Index Scan
해당 공유 해시 테이블과 일치시킬 수 있습니다. SQL Server 2012에서는 유출로 인해 운영자가 행 모드에서 다시 시작하여 배치 모드의 이점을 잃고 Repartition Streams
조인의 프로브 측에 운영자가 스레드 스큐를 일으킬 수 있기 때문에 예측하기가 훨씬 어려웠습니다. . 유출이 배치 모드로 유지되도록하는 것은 SQL Server 2014에서 크게 개선되었습니다.
내 지식으로는 행 모드에는이 공유 해시 테이블 기능이 없습니다. 그러나 경우에 따라 일반적으로 빌드 쪽에서 행 수가 100 개 미만인 SQL Server는 각 스레드에 대해 별도의 해시 테이블 복사본을 만듭니다 ( Distribute Streams
해시 조인으로 선행하여 식별 가능 ). 이것은 매우 강력 할 수 있지만 카디널리티 예상 값에 따라 다르며 SQL Server는 각 스레드에 대한 해시 테이블의 전체 복사본을 작성하는 비용과 비교하여 이점을 평가하려고하기 때문에 배치 모드보다 훨씬 덜 안정적입니다.
UNION ALL : 더 간단한 대안
Paul White는 또 다른 잠재적으로 더 간단한 옵션은 UNION ALL
각 값의 행을 결합하는 데 사용 하는 것이라고 지적했습니다 . 이 SQL을 동적으로 쉽게 구축 할 수 있다고 가정하면 가장 좋은 방법 일 것입니다. 예를 들면 다음과 같습니다.
SELECT 'A' AS Col0, c.DataA AS Col1
FROM ColumnstoreTable c
UNION ALL
SELECT 'B' AS Col0, c.DataB AS Col1
FROM ColumnstoreTable c
UNION ALL
SELECT 'C' AS Col0, c.DataC AS Col1
FROM ColumnstoreTable c
또한 배치 모드를 사용할 수 있고 원래 답변보다 더 나은 성능을 제공하는 계획을 산출합니다. (두 경우 모두 성능이 빠르기 때문에 데이터를 테이블에 선택하거나 테이블에 쓰면 신속하게 병목 현상이 발생합니다.)이 UNION ALL
방법은 0을 곱하는 것과 같은 게임은 피합니다. 때로는 단순하게 생각하는 것이 가장 좋습니다!
CPU time = 8673 ms, elapsed time = 4270 ms.