연결 물리적 조작 : 실행 순서를 보장합니까?


12

표준 SQL에서 결과는 union all어떤 순서로도 보장되지 않습니다. 따라서 다음과 같은 것이 있습니다.

select 'A' as c union all select 'B'

순서에 관계없이 두 행을 반환 할 수 있습니다 (실제로 'A'가 'B'보다 앞에 올 것이라는 것을 알고있는 데이터베이스에서 실제로도).

SQL Server에서는 "연결"물리적 작업을 사용하여 실행 계획으로 바뀝니다.

연결 연산이 입력을 스캔하여 사용 가능한 레코드가있는 입력을 리턴한다고 쉽게 상상할 수 있습니다. 그러나 웹에서 다음 문장을 찾았습니다 ( here ).

쿼리 프로세서는 연산자가 계획에 나타나는 순서대로이 계획을 실행합니다. 첫 번째는 최상위이고 마지막은 끝입니다.

질문 : 실제로 이것이 사실입니까? 이것이 사실입니까?

Microsoft 설명서에서 입력이 처음부터 끝까지 순서대로 스캔된다는 참조를 찾지 못했습니다. 반면에, 그것을 실행할 때마다 결과는 입력이 실제로 순서대로 처리되었음을 나타냅니다.

엔진이 한 번에 두 개 이상의 입력을 처리하는 방법이 있습니까? 내 테스트 (상수보다 훨씬 복잡한 표현을 사용)는 병렬 지원 8 코어 시스템에서 수행되며 대부분의 쿼리는 병렬 처리를 이용합니다.

답변:


10

아니요 . Microsoft의 동작을 보증하는 문서가 없으므로 보장되지 않습니다 .

또한 Simple Talk 기사가 정확하고 Concatenation 실제 연산자가 항상 계획에 표시된 순서대로 입력을 처리한다고 가정하면 (매우 사실 일 수 있음) SQL Server가 항상 동일한 계획을 유지한다는 보장없이 쿼리 텍스트와 쿼리 계획 사이의 순서는 약간 나을뿐입니다.

우리는 이것을 더 조사 할 수 있습니다. 쿼리 최적화 프로그램이 연결 연산자 입력을 재정렬 할 수있는 경우, 문서화되지 않은 DMV에 sys.dm_exec_query_transformation_stats해당 최적화에 해당하는 행이 있어야합니다 .

SELECT * FROM sys.dm_exec_query_transformation_stats 
    WHERE name LIKE '%CON%' OR name LIKE '%UNIA%'

SQL Server 2012 Enterprise Edition에서는 24 행이 생성됩니다. 상수와 관련된 변환에 대한 잘못된 일치를 무시하면 Concatenation Physical Operator UNIAtoCON(Union All to Concatenation) 와 관련된 변환이 하나 있습니다. 따라서 실제 연산자 레벨에서 연결 연산자를 선택하면 해당 연산자가 파생 된 논리적 전체 연합 연산자의 순서대로 처리됩니다.


사실 그것은 사실이 아닙니다. 비용 기반 최적화가 완료된 후 물리적 연결 연산자에 입력을 다시 정렬 할 수있는 최적화 후 재 작성이 있습니다. 하나의 예는 연결이 행 목표에 종속 될 때 발생합니다 (따라서 더 저렴한 입력에서 먼저 읽는 것이 중요 할 수 있습니다). 자세한 내용 은 Paul White의 UNION ALL최적화 를 참조하십시오.

이 물리적 재 작성은 SQL Server 2008 R2까지 작동했지만 회귀는 더 이상 SQL Server 2012 이상에 적용되지 않았습니다. 쿼리 최적화 프로그램 핫픽스 (예 : 추적 플래그 4199)를 사용하여 SQL Server 2014 이상 (2012가 아님)에 대한이 다시 쓰기를 복원 하는 수정 프로그램이 발행되었습니다 .


그러나 Logical Union All 연산자 ( UNIA)는 어떻습니까? UNIAReorderInputs입력을 재정렬 할 수 있는 변환이 있습니다. 논리적 인 Union All UNIAtoCONUNIAtoMERGE(Union All to Merge Union) 을 구현하는 데 사용할 수있는 두 개의 실제 연산자도 있습니다 .

따라서 쿼리 최적화 프로그램 이 ;에 대한 입력을 다시 정렬 할 수 있는 것으로 보입니다 UNION ALL. 그러나 일반적인 변환 UNIAReorderInputs은 아닙니다. 쉽게 액세스 할 수있는 SQL Server에서 0 번 사용 하는 경우가 있습니다 UNIAReorderInputs. 계획 지침서 또는 사용시 반드시 사용되지만 최적화 프로그램을 사용할 상황을 알 수 없습니다. plan hint는 위에서 언급 한 행 목표 물리적 재정렬 입력을 사용하여 생성 된 계획을 강제 실행하는 데 사용됩니다.

엔진이 한 번에 두 개 이상의 입력을 처리하는 방법이 있습니까?

연결 물리적 연산자는 계획의 병렬 섹션 내에 존재할 수 있습니다. 약간의 어려움으로 다음 쿼리를 사용하여 병렬 연결로 계획을 작성할 수있었습니다.

SELECT userid, regdate  FROM (  --Users table is around 3mil rows
    SELECT  userid, RegDate FROM users WHERE userid > 1000000
    UNION 
    SELECT  userid, RegDate FROM users WHERE userid < 1000000
    UNION all
    SELECT userid, RegDate FROM users WHERE userid < 2000000
    ) d ORDER BY RegDate OPTION (RECOMPILE)

따라서 가장 엄격한 의미에서 물리적 연결 연산자는 항상 일관된 방식으로 입력을 처리하는 것처럼 보입니다 (맨 위, 맨 아래). 그러나 옵티마이 저는 실제 연산자를 선택하기 전에 입력 순서를 전환하거나 연결 대신 병합 통합을 사용할 수 있습니다.


8

Craig Freedman 에 따르면 연결 연산자의 실행 순서가 보장됩니다.

MSDN 블로그 에서 자신의 블로그 게시물 조회 계획보기 :

운영자에게 둘 이상의 자녀가있는 경우 자녀의 순서가 중요합니다. 가장 위의 아이는 첫 번째 아이이고 가장 아래의 아이는 두 번째 아이입니다. 연결 연산자는 하위를이 순서대로 처리합니다.

온라인 서적 쇼 플랜 ​​논리 및 물리 연산자 참조 서

연결 실제 연산자에는 둘 이상의 입력과 하나의 출력이 있습니다. 연결은 첫 번째 입력 스트림에서 출력 스트림으로 행을 복사 한 다음 각 추가 입력 스트림에 대해이 작업을 반복합니다.


그 인용문은 내가 찾던 것과 아주 가깝습니다. 문서 가이 경우 병렬 처리를 배제하는 것이 실망 스럽지만 순서대로 실행되지 않고 그 순서대로 반환되도록 기꺼이 도와 드리겠습니다.
Gordon Linoff

2

커뮤니티 위키 답변 :

반례를 만들 수 없다면 관찰 된 행동이 항상 어떤 방식 으로든 보장된다는 것을 증명할 수 있는지 모르겠습니다. 그렇지 않으면 결과가 반환되는 순서를 수정하는 방법은 물론을 추가하는 것 ORDER BY입니다.

"수정"이 있는지 또는 수정이 필요한지 모르겠습니다. 일부 시나리오에서 쿼리가 다른 순서로 처리된다는 것을 보여줄 수 있습니다.

명시적이고 공식적인 문서가 없기 때문에 이에 의존해서는 안된다고 제안합니다. 이것은에 문제로 사람들을 가지고 것은 정확히 종류의 ORDER BY뷰, 그리고 GROUP BY없이 ORDER BYSQL 서버 2005의 최적화가 출시되었을 때 팔년 전.

최신 버전의 SQL Server (모든 기능이 추가됨)의 모든 새로운 기능을 사용하면 오늘날 특정 동작을 보장 할 수 있다고 생각하더라도 사실대로 유지 될 것으로 기대하지는 않습니다 (문서화 될 때까지).

이 동작에 의존하지 않더라도 결과로 무엇을 하시겠습니까? 어쨌든, 나는 외부 담당자에 의해 간단한 대화 기사를 부르지 않을 것 입니다. 우리 모두는 이것이 관찰에 근거한 추측 일 뿐이라는 것을 알고 있습니다.

Microsoft는 'x'가 'y'를 보장 하지 않는다는 공식 문서를 게시 하지 않습니다 . 이것은 거의 10 년이 지난 지금도 사람들이 관찰 된 주문에 의존 할 수 없다는 확신을 얻는 데 어려움을 겪는 이유 중 하나입니다 ORDER BY. "보증되지 않는다"는 문서는 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.