2017-12-27 4 views
2

나는 앵커가 필요하다는 것을 알게된다. 그리고 UNION ALL이 필요하다는 것을 알고 있습니다. 재귀 CTE에없는 경우에는 작동하지 않지만 ... 왜 그런지에 대한 좋은 설명을 찾을 수 없습니다. 모든 문서에는 단지 당신이 필요하다고 명시되어 있습니다.Transact-SQL에서 재귀 CTE가 UNION이 아닌 UNION ALL을 필요로하는 이유는 무엇입니까?

이유가 일 수 없다 재귀 쿼리에서 UNION ALL 대신 UNION을 사용합니까? 그것은 더 깊은 재귀에 중복을 포함시키지 않는 것이 좋은 생각 인 것 같습니다, 그렇죠? 그런 식으로 이미 후드 아래에서 작동해야합니다, 나는 생각합니다.

+0

우리는 당신이 의미하는 것을 얻지 못하기 때문에 약간의 코드를 볼 수 있습니까? – Sami

+0

Downvoter 관심을 갖는 분? –

+0

@Sami 재귀 적 CTE의 정의는 재귀 쿼리에 앵커 쿼리'UNION ALL'을 요구합니다. 왜 유니온이 아닌 유니온이 될 필요가 있는지 묻고 있는데 옵티마이 저가 이미 어떤 형태로하고 있다고 생각합니다. –

답변

2

이유는 구현할 가치가있는 우선 순위 기능이라고 생각하지 않았기 때문입니다. Postgres does support bothUNIONUNION ALL처럼 보입니다.

이 기능에 대한 강력한 사례가 있다면 Connect (또는 대체 할 URL이 무엇이든간에) 의견을 제공 할 수 있습니다.

후속 단계에서 이전 행에 추가 된 중복 행이 거의 언제나 무한 루프를 발생 시키거나 최대 재귀 제한을 초과하게되므로 중복을 방지하면 유용합니다. 코드가 UNION 등이 문서에서는 they are implemented in SQL Server 설명 enter image description here

다음과 같이 시연 사용하는 경우

SQL Standards 꽤 몇 군데 있습니다. 그들은 "두포"처럼 아무것도하지 않습니다. 스택 스풀은 행이 삭제 될 때 행을 삭제하므로 나중에 행이 삭제 된 행의 사본인지 여부를 알 수 없습니다. UNION을 지원하려면 다소 다른 접근 방식이 필요합니다.

그 사이에 TVF의 멀티 서술에서 동일한 결과를 얻을 수 있습니다.

UNION ALLUNION을 변경하고 무한 재귀에서 당신을 저장하지 않습니다 끝에 DISTINCT를 추가 ( Postgres Fiddle)

WITH R 
    AS (SELECT 0 AS N 
     UNION 
     SELECT (N + 1)%10 
     FROM R) 
SELECT N 
FROM R 

아래 바보 같은 예를 취합니다.

하지만 당신은 위의 중복을 폐기 IGNORE_DUP_KEY을 사용

CREATE FUNCTION dbo.F() 
RETURNS @R TABLE(n INT PRIMARY KEY WITH (IGNORE_DUP_KEY = ON)) 
AS 
    BEGIN 
     INSERT INTO @R 
     VALUES  (0); --anchor 

     WHILE @@ROWCOUNT > 0 
     BEGIN 
      INSERT INTO @R 
      SELECT (N + 1)%10 
      FROM @R 
     END 

     RETURN 
    END 

GO 

SELECT * 
FROM dbo.F() 

으로이를 구현할 수 있습니다. 열 목록의 너비가 너무 커서 색인을 생성 할 수없는 경우 DISTINCTNOT EXISTS이 필요합니다. 또한 재귀의 최대 횟수를 설정하고 무한 루프를 피하는 매개 변수가 필요할 수도 있습니다.

+0

... 기본적으로 SQL Server의 기술적 제한 사항입니다. 흥미 롭 군! –

+1

부수적으로, 저는 실제로 UNION을 사용할 필요가 없습니다. 오랫동안 직관력이 떨어지는 것처럼 보였습니다. 어제 마침내 왜 연구 할만한지 궁금해졌습니다. . –

2

이것은 순수한 추측이지만 각 반복의 결과를 개별적으로 계산할 수 있다는 UNION ALL의 보장이 있습니다. 본질적으로 반복은 다른 것과 간섭 할 수 없다는 것을 보장합니다.

UNION은 이전 반복의 결과를 수정할 수있는 백그라운드에서 정렬 작업을 요구합니다. 프로그램은 호출 스택에서 이전 호출의 상태를 변경해서는 안되며 입력 매개 변수와 후속 반복의 결과를 사용하여 호출 스택과 상호 작용해야합니다 (절차 설정에서). 이것은 아마도 SQL Server의 재귀 적 CTE에 따라 집합 기반 연산에 적용되어야합니다.

내가 잘못 될 수도, 늦은 밤 뇌 덤프는 신뢰성이 100 % :

편집 (또 다른 생각)하지 :

재귀 시작, 당신은 호출 스택을

. 이 스택의 각 레벨은 결과 계산을 시작하지만 모든 후속 호출의 결과가 끝나기 전에 결과를 반환해야합니다. UNION은 중복을 제거하려고 시도하지만 종료 조건에 도달 할 때까지 레코드를 보유하지는 않지만 (최종 레코드는 아래에서 위로 작성됩니다), 후속 호출의 결과는 위 조건에 의해 요구됩니다 . UNION은 끝에서 DISTINCT로 축소됩니다.

+0

각 호출마다 스택에 각 재귀를 추가하지 않고 완료시 자체를 제거하지 않습니까? 그것이 사실이라면 그것이 진행될 때 중복 될 것이라고 나는 생각할 것입니다. –

+0

이것이 최상의 솔루션 성능을 발휘할 수 있는지 확실하지 않습니다. 즉, 각 반복 후에 정렬 및 비교가 발생해야합니다. 나는 최종 결과를 계산 한 후에 그것을하는 것이 많은 경우에 더 적합하다는 것을 말할 것이다. 편집에서 호출 스택은 프로 시저 재귀가 작동하는 방식에서 파생됩니다. SQL Server 최적화 도구는 잘못되었을 수 있습니다. – Pred

+0

끝에서하는 것은 동일하지 않습니다. 그것은 종료 또는 무한 루프 간의 차이를 만들 수 있습니다. –

관련 문제