이 특정 중복 파생 테이블에 대해 주문이 보장되지 않을 가능성이 있습니까?


12

나는 Lukas Eder와의 트위터 대화 에서이 질문을 우연히 발견했다 .

올바른 동작은 가장 바깥 쪽 쿼리에 ORDER BY 절을 적용하는 것이지만 여기서는 가장 바깥 쪽 쿼리에 DISTINCT, GROUP BY, JOIN 또는 다른 WHERE 절을 사용하지 않기 때문에 RDBMS가 왜 내부 쿼리로 정렬 된 수신 데이터?

SELECT * 
FROM (
    SELECT * FROM table ORDER BY time DESC
) AS t

PostgreSQL에서이 예제를 실행하면 최소한 내부 쿼리와이 파생 테이블 예제 및 동일한 결과 집합에 대해 동일한 실행 계획이 제공됩니다.

따라서 Planner는 중복되거나 내부 테이블의 결과를 통과하기 때문에 가장 바깥 쪽 쿼리를 단순히 버릴 것이라고 가정합니다.

아무도 이것이 그렇지 않을 것이라고 생각합니까?


4
파생 테이블 내에서 order by를 사용할 수 없으므로 SQL Server에서 쿼리가 실패합니다.
a_horse_with_no_name

왜 그렇게 믿어? 왜 당신은 무엇을 가정합니까? 선택의 여지를 남기는 프로그램을 작성할 때 사용자가 선택에 대한 것을 기대할 것입니까? 논리적 및 물리적 쿼리 최적화 / 구현에 대해 읽으십시오.
philipxy

2
"계획자가 중복되거나 내부 테이블의 결과를 통과하기 때문에 Planner가 가장 바깥 쪽 쿼리를 단순히 삭제한다고 가정합니다." 컨텍스트에서 의미 가 없으므로 Planner가 내부 쿼리 에서 ordering 절 을 삭제한다고 쉽게 가정 할 수 있습니다 .
와일드 카드

2012 년경 MariaDB가이 문제에 대해 논의합니다. 내부 부족은 그룹 별 max에 대한ORDER BY 다른 최적화로 이어집니다.
Rick James

1
실제로, 당신은 Postgres에 적합합니다.
Erwin Brandstetter

답변:


20

대부분의 데이터베이스는 ORDER BY하위 쿼리에서 다음 중 하나 라는 사실에 대해 매우 분명 합니다.

  • 허용되지 않음 : 예 : SQL Server, Sybase SQL Anywhere ( TOP또는로 보완되지 않는 한 OFFSET .. FETCH)
  • 의미 없음 : 예 : PostgreSQL, DB2 ( OFFSET .. FETCH또는로 보완하지 않는 한 LIMIT)

다음은 DB2 LUW 매뉴얼 (강조 광산)의 예입니다.

부속 선택의 ORDER BY 절 은 조회가 리턴 한 행 순서에 영향을 미치지 않습니다 . ORDER BY 절은 가장 바깥 쪽 fullselect에 지정된 경우 리턴 된 행의 순서에만 영향을줍니다.

PostgreSQL과 마찬가지로 표현은 매우 명시 적입니다 .

정렬을 선택하지 않으면 행이 지정되지 않은 순서로 반환됩니다. 이 경우 실제 순서는 스캔 및 결합 계획 유형 및 디스크 순서에 따라 달라 지지만 의지하지 않아야합니다 . 정렬 단계가 명시 적으로 선택된 경우에만 특정 출력 순서를 보장 할 수 있습니다.

이 사양 ORDER BY에서 파생 테이블 의 절에서 생성 된 순서 는 우연히 발생하는 것으로 예상되는 순서 (사소한 예에서는 대부분의 데이터베이스에서 발생하는 순서)와 일치 할 수 있지만이 방법을 사용하는 것은 현명하지 않습니다. 이.

DB2에 대한 참고 사항 :

특히, DB2에는 알려진 기능이 적ORDER BY ORDER OF <table-designator> 으며 다음과 같이 사용할 수 있습니다.

SELECT C1 FROM
   (SELECT C1 FROM T1
      UNION
    SELECT C1 FROM T2
    ORDER BY C1 ) AS UTABLE
ORDER BY ORDER OF UTABLE

이 경우 파생 테이블의 순서는 가장 바깥 쪽 SELECT에서 명시 적으로 재사용 할 수 있습니다.

오라클에 대한 참고 사항 :

수년 동안 오라클은을 OFFSET사용하여 페이지 매김 을 구현하는 관행 이었으며 파생 테이블 주문한 후에ROWNUM 만 합리적으로 계산할 수 있습니다 .

SELECT *
FROM (
  SELECT rownum AS rn, t.* -- ROWNUM here depends on the derived table's ordering
  FROM (
    SELECT * FROM table ORDER BY time DESC
  ) t
) t
WHERE rn BETWEEN 10 AND 20

적어도 ROWNUM쿼리에 존재 한다면, 미래의 Oracle 버전은 기존의 모든 Oracle SQL을 거의 파괴하지 않기 위해이 동작을 중단하지 않을 것으로 예상 할 수 있습니다. 읽을 수있는 SQL 표준 OFFSET .. FETCH구문 :

SELECT * FROM table ORDER BY time DESC OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY

Meaningless: E.g. PostgreSQL정말해야한다 '신뢰할 수없는',이 때문에 않는 평균 뭔가를. 행은 내부 쿼리에서 정렬되며, 별도의 지시가 없거나 추가 순서가 필요한 순서가없는 한 순서는 외부 쿼리 수준으로 유지됩니다. 그것이 구현 세부 사항 일지라도 의미가 없습니다. 정렬 된 입력에 함수를 집계하는 데 사용할 수 있습니다. 만큼 수동 심지어 힌트 : Alternatively, supplying the input values from a sorted subquery will usually work.
어윈 Brandstetter

Postgres에 추가 한 견적은 실제로 다른 경우에 적용됩니다 : 전혀없는 쿼리 ORDER BY.
Erwin Brandstetter

@ ErwinBrandstetter : 그 세부 사항에 대한 답변을 자유롭게 추가하십시오. 나는 구현 세부 사항이 의미가 있다고 개인적으로 동의하지 않습니다. 바로 오늘, 사람들은 Oracle 8i에서 오라클이 항상 정렬 그룹을 수행하는 것에 의존한다는 것을 알게되었습니다. 주문에 의존 할 수 있습니다. 다시 말해, 나는 그것을 대담한 말로 표현하고 싶다. 의미없는 것은 , 오, xyz 버전의 복잡한 세부 사항을 알고 있다면 실제로 할 수있는 것입니다.
Lukas Eder

이미 답변을 추가했습니다. 우리가 비표준 행동을 무시하기로 선택했는지 또는 우리가 가진 다른 좋은 조언은 질문 옆에 있습니다 : 주어진 쿼리에 대해 순서가 보장됩니까? Postgres를위한 것입니다. 다른 RDBMS에는 적용되지 않습니다. 그리고 그것은 xyz 버전뿐만 아니라 기존의 모든 Postgres 버전 에도 적용됩니다 (예약 포함). 귀하의 인용문이 잘못되었습니다. 비표준 동작을 무시하고 싶다면 Oracle로 시작하여 NULL과 빈 문자열이 동일하다고 생각할 수 있습니다. 또한 질문과 직교합니다.
Erwin Brandstetter

@ErwinBrandstetter : 흥미로운, 업데이트 주셔서 감사합니다. 이것이 문서화 된 내용을 보증하는 것입니까?
루카스 Eder

12

예. ORDER BY절이 없으면 출력 순서가 정의되지 않으며 쿼리 플래너는 사용자가 이것을 알고 이해한다고 가정 할 수있는 범위 내에 있습니다.

외부 쿼리는 순서를 지정하지 않기 때문에 정렬 작업을 피하기 위해 내부 쿼리에서 순서를 제거 할 수 있습니다 (특히 클러스터링 된 인덱스가 없거나 순서를 지원할 인덱스가없는 경우). 그렇지 않은 경우 지금 은 향후 버전에서 할 수 있습니다.

정의되지 않은 행동에 의존하지 마십시오. 특정 주문이 필요한 경우 ORDER BY적절한 장소에 조항을 제공하십시오.


PostgreSQL에서 테스트 할 때 ORDER BY에서 사용하는 열에 인덱스가 없으므로 순차적 스캔 후 정렬이 수행되었습니다. 내부 쿼리 ORDER BY를 건너 뛸 것으로 생각되는 RDBMS는 무엇입니까?
Vlad Mihalcea

5
나는 그들이 무엇을 것인지 알 수 없다 . 단지 그들이 원한다면 그들 모두가 완전하게 자유롭게 할 수있다. 그것은 일반적인 표준과 제품 사양에 따라 완벽하게 수용 가능한 최적화 일 것이다. SQL Server는 쿼리를 완전히 거부합니다 (포함하지 않는 한 TOP 100%현재 쿼리가 이식 가능하지 않은 경우 프로젝트의 우선 순위 여야 함). 사실 구 버전은 그럴 것입니다. 그래서 만약을 대비하여 행동에 의존하지 않아야합니다.
David Spillett


6

정의되지 않은 동작의 문제입니다-당신을 위해 일하고, 나를 위해 일하고, HDD를 prod로 다시 포맷합니다.)

한 걸음 물러서서 어떤 의미에서든 옳다고 말할 수 있습니다. 제정신 RDBMS가 내부 선택에서 행을 재 배열해야 할 이유가 없습니다. 그러나 보장되지는 않습니다. 향후에 이유가있을 수 있으며 공급 업체는 자유롭게 할 수 있습니다. 이는이 행동에 의존하는 코드가 API POV의 주요 변경 사항이 아니기 때문에 공급 업체가 공개 할 의무가없는 변경을 자비로한다는 것을 의미합니다.


2
주문을 밖으로 최적화 할 수있는 한 가지 이유는 속도입니다. 다른 순서로 행을 반환하는 것이 더 효율적일 수 있습니다.
TomTom

2
특히, 서버는 병렬 처리를 이용하여 테이블을 읽을 수 있습니다. 그렇다면 주문을 시행 할 필요가 없다면 행을 다시 가져 오지만 스레드는 읽습니다. (SQL Server는 실제로 그렇게하는 것이이 작업을 수행 SELECT아니오 ORDER BY. 정말이 결정적, 이론 또는 데이터가 변경 되었기 때문에 단지입니다)
제론 Mostert

@JeroenMostert : 정의되지 않은 동작은 더욱 악화됩니다. 순서가 맞지 않고 델타를 사용하여 배열에 색인을 생성하면 어떻게됩니까?
여호수아

2

이 특정 중복 파생 테이블에 대해 주문이 보장되지 않을 가능성이 있습니까?

현재 존재하는 모든 Postgres (테스트중인) 버전에 대한 답변 은 다음과 같습니다. 아니요 -이 특정 쿼리에 대해. 정렬 순서가 보장됩니다.

Microsoft는 ORDER BY하위 쿼리를 허용하지 않기 때문에 SQL 서버 사용자는 불편할 것 입니다. 그럼에도 불구하고 Postgres에서이 간단한 쿼리에 대해서는 정렬 순서가 보장됩니다. ORDER BY는 하위 쿼리에 적용되며 외부 쿼리는 순서를 변경할 수있는 작업을 수행하지 않습니다.

매뉴얼은 집계 함수 장에서 많은 힌트를 얻습니다 .

또는 정렬 된 하위 쿼리에서 입력 값을 제공하면 일반적으로 작동합니다.

외부 쿼리 수준이 순서를 변경할 수있는 작업을 추가하지 않는 경우에만 해당됩니다. 따라서 간단한 경우에는 "보증 된"것이므로 SQL 표준의 지원을받지 않습니다. 추가 작업이 필요한 경우 Postgres를 무료로 재주문 할 수 있습니다. 의심스러운 경우 ORDER BY외부 에 다른 것을 추가하십시오 SELECT. (이 경우 내부 ORDER BY는이 간단한 쿼리에서 중복 노이즈가됩니다.)


"table"단순한 기본 테이블이 아니라 복잡한 뷰 또는 파티션 된 테이블 인 경우에 해당됩니까? 계획이 병렬로 실행되는 것도 사실입니까? Postgres 10에서도 마찬가지입니까? (이 질문에 대한 답은 확실하지 않습니다.)
ypercubeᵀᴹ

@ ypercubeᵀᴹ : Postgres 10을 테스트하지는 않았지만 어쨌든 사실입니다. 간단한 경우에 대한 외부 쿼리에서 순서가 적용되고 변경되지 않습니다.
Erwin Brandstetter
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.