2011-03-15 5 views
16

일부 영구 데이터가있는 테이블이 있습니다. 이제 쿼리 할 때 결과에 ​​필요한 값을 계산하고 누락 된 행을 영구 테이블에 삽입해야하는 꽤 복잡한 CTE가 있습니다. 결국 나는 CTE에 의해 식별 된 모든 행으로 구성된 결과를 선택하려고하지만 테이블에 이미있는 경우 테이블의 데이터로 선택하려고합니다. 행 삽입 여부에 관계없이 정보가 필요합니다. 나는 WHEN MATCHED THEN UPDATE 부분이 마음에 들지SQL MERGE 문에서 UPDATE-no-op

-- Set-up of test data, this would be the persisted table 
DECLARE @target TABLE (id int NOT NULL PRIMARY KEY) ; 
INSERT INTO @target (id) SELECT v.id FROM (VALUES (1), (2)) v(id); 

-- START OF THE CODE IN QUESTION 
-- The result table variable (will be several columns in the end) 
DECLARE @result TABLE (id int NOT NULL, new bit NOT NULL) ; 

WITH Source AS (
    -- Imagine a fairly expensive, recursive CTE here 
    SELECT * FROM (VALUES (1), (3)) AS Source (id) 
) 
MERGE INTO @target AS Target 
    USING Source 
    ON Target.id = Source.id 
    -- Perform a no-op on the match to get the output record 
    WHEN MATCHED THEN 
     UPDATE SET Target.id=Target.id 
    WHEN NOT MATCHED BY TARGET THEN 
     INSERT (id) VALUES (SOURCE.id) 
    -- select the data to be returned - will be more columns 
    OUTPUT source.id, CASE WHEN $action='INSERT' THEN CONVERT(bit, 1) ELSE CONVERT(bit, 0) END 
     INTO @result ; 

-- Select the result 
SELECT * FROM @result; 

차라리 중복 업데이 트를 떠날 것,이는 다음과 같이 작동 단순화

(당신이 그것을 시도하려는 경우 다음 코드는 일반 쿼리로 실행) 멀리하지만 OUTPUT 절에 결과 행이 표시되지 않습니다.

이런 종류의 데이터를 완료하고 반환하는 가장 효율적인 방법입니까?

또는 new=0이다 행의 INSERT 수행 후 SELECT와 함께 그 결과를 미리 계산함으로써 인스턴스 MERGE없이 더 효율적인 솔루션을있을 것인가? 쿼리 계획을 해석하는 데 어려움이 있습니다. 기본적으로 성능이 현저하게 떨어지는 "클러스터 된 인덱스 병합"이 SELECT에 이어 INSERT 변형에 이어집니다. 그리고 SQL Server (2008 R2 with CU1)가 실제로 똑똑해서 UPDATE이 no-op (예 : 쓰기 필요 없음)인지 알 수 있을지 궁금합니다.

+1

나는 with, merge 및 redundant update와 동일한 설정을 가지고 있으며 실제로 업데이트를 수행하지 않지만 여전히 ID를 반환하는 솔루션을 찾고 있습니다. 해결책을 찾으면 그것을 추가하십시오 =) –

+0

RE : 비 업데이트 업데이트 여기 설명 된대로 클러스터링 키의 일부가 아닌 열에서 No-OP 업데이트를 수행하는 것이 좋습니다 (가능한 경우) //sqlblog.com/blogs/paul_white/archive/2010/08/11/the_2D00_impact_2D00_of_2D00_update_2D00_statements_2D00_that_2D00_don_2D00_t_2D00_change_2D00_data.aspx –

+0

@David Mårtensson, 현상금을 추가해 주셔서 감사합니다. :) – Lucero

답변

23

더미 변수를 선언하고 WHEN MATCHED 절에 값을 설정할 수 있습니다.

DECLARE @dummy int; 
... 
MERGE 
... 
WHEN MATCHED THEN 
    UPDATE SET @dummy = 0 
... 

실제 테이블 업데이트보다 비용이 적게 듭니다.

+0

그것은 훌륭한 아이디어이며 잘 작동하는 것 같습니다. 누군가가 뭔가 더 잘 떠오르면 대답으로 받아 들일 것입니다 ... '병합 (MERGE)'에서 시간의 1/3을 차지하는 것처럼 보입니다. – Lucero

+0

이 솔루션은 적어도 100 rep bounty =의 가치가있는 제 문제를 해결했습니다. 답변과 좋은 질문에 대해서는 Andriy와 Lucero에게 감사드립니다. –

+0

@David, 감사합니다! 이것은 참으로 좋은 질문입니다. 그런 것들은 필요한 지식을 필요로하는 실제 문제가 생길 때까지 기다리기보다는 사전에 알고있는 가치가있는 경우가 많습니다. –

관련 문제