RANK () 및 DENSE_RANK ()는 결정적입니까 아니면 비 결정적입니까?


27

공식 Microsoft BOL 에 따르면 DENSE_RANK는 비 결정적입니다 ( RANK () ). 그러나 Itzik Ben-Gan의 순위 함수에 따르면 "... RANK () 및 DENSE_RANK () 함수는 항상 결정적입니다." 누구가 옳습니까?

지금까지 내가 찾은 것 : Microsoft의 정의 "결정적 함수는 특정 입력 값 세트로 호출되고 데이터베이스의 동일한 상태가 제공 될 때마다 항상 동일한 결과를 리턴합니다."

Set 이론 테이블에서

Employee            Salary
Sue Right            1.00
Robin Page           1.00
Phil Factor          1.00

직원 2

Employee            Salary
Phil Factor          1.00
Sue Right            1.00
Robin Page           1.00

동일합니다. 그러나 순위 함수는 다른 값을 반환합니다.

    CREATE TABLE [dbo].[Employees](
    --[ID] [int] IDENTITY(1,1) NOT NULL,
    [Employee] [varchar](150) NOT NULL,
    [Salary] [smallmoney] NULL,
) ON [PRIMARY]

GO
CREATE TABLE [dbo].[Employees2](
    --[ID] [int] IDENTITY(1,1) NOT NULL,
    [Employee] [varchar](150) NOT NULL,
    [Salary] [smallmoney] NULL,
) ON [PRIMARY]

INSERT INTO [dbo].[Employees]
([Employee] ,[Salary])
VALUES
('Sue Right', 1)
, ('Robin Page', 1)
,('Phil Factor', 1 )
GO
INSERT INTO [dbo].[Employees2]
([Employee] ,[Salary])
VALUES
('Phil Factor', 1 )
,('Sue Right', 1)
,('Robin Page', 1)
GO
SELECT RANK() OVER ( ORDER BY Salary) AS [Rank]
, DENSE_RANK() OVER (ORDER BY Salary ) AS [Dense_rank]
, [Employee]
FROM
dbo.Employees

SELECT RANK() OVER ( ORDER BY Salary) AS [Rank]
, DENSE_RANK() OVER (ORDER BY Salary ) AS [Dense_rank]
, [Employee]
FROM
dbo.Employees2

SELECT NTILE(3) OVER ( ORDER BY SALARY )
, [Employee]
FROM
dbo.Employees

SELECT NTILE(3) OVER ( ORDER BY SALARY )
, [Employee]
FROM
dbo.Employees2

답변:


23

공식 Microsoft BOL에 따르면 DENSE_RANK는 비 결정적입니다 (RANK ()). 그러나 Itzik Ben-Gan의 순위 함수에 따르면 "... RANK () 및 DENSE_RANK () 함수는 항상 결정적입니다." 누구가 옳습니까?

그들은 "결정 론적"이라는 단어의 다른 의미를 사용하기 때문에 둘 다 맞습니다.

SQL Server 최적화 프로그램의 관점에서 "결정적"은 매우 정확한 의미를 갖습니다. 윈도우 및 순위 기능이 제품에 추가되기 전에 존재했던 의미. 옵티 마이저에게 "결정적"특성은 최적화 중에 함수가 내부 트리 구조 내에서 자유롭게 복제 될 수 있는지 여부를 정의합니다. 비 결정적 기능에는 적합하지 않습니다.

여기서 결정적 의미는 함수의 정확한 인스턴스가 호출 횟수에 관계없이 항상 동일한 입력에 대해 동일한 출력을 반환한다는 의미입니다. (단일 행) 스칼라 함수로서 행 내 또는 행간에 동일한 결과를 반환하지 않기 때문에 정의에 따라 윈도우 함수에는 적용되지 않습니다. 간단히 말해서 ROW_NUMBER예를 들어 사용하십시오.

ROW_NUMBER함수는 정의에 따라 다른 행에 대해 다른 값을 반환하므로 최적화 목적으로 결정적이지 않습니다.

이것이 BOL이 사용하는 의미입니다.

Itzik은 결과의 전체 결정론에 대해 다른 점을 지적하고 있습니다. 순서에 맞는 입력 세트 (적절한 타이 브레이킹 포함)에서 출력은 "결정적"순서입니다. 이는 유효한 관찰이지만 쿼리 최적화 중에 중요한 "결정적"품질이 아닙니다.


10

NTILE()흥미로운 경우입니다. 정렬 후 적용되는 것 같습니다 (동점 인 경우 SQL Server의 자체 장치에 남게되며 이는 일반적으로 정렬을 위해 가장 효율적인 인덱스 선택에 의해 결정됩니다). SQL Server가 여기에서 임의의 선택을하지 않도록함으로써이 결정론을 만들 수 있습니다. OVER()절 에 하나 이상의 타이 브레이커를 추가하십시오 .

OVER (ORDER BY Salary, Employee)

기본적으로 정렬을 고유하게 만들어야합니다. 이름이 같은 직원이있는 경우 다른 타이 브레이커 열을 선택하거나 관계가 없을 때까지 열을 계속 추가해야 할 수 있습니다.

들어 RANK()DENSE_RANK(), 넥타이는 것이 중요한 이유가 실제로 할 수없는 서로 다른 값을 가져가. 함수 출력의 결정론과 결과 순서의 결정론을 혼동하지 마십시오. 귀하의 검색어에가 없으면 ORDER BY어떻게 결정적이지 않습니까?

1   1   Sue Right
1   1   Robin Page
1   1   Phil Factor

1   1   Phil Factor
1   1   Sue Right
1   1   Robin Page

RANK()그리고 DENSE_RANK()두 경우 모두 같은 값을 적용, SQL 서버는 다른 순서로 당신에게 결과를 반환했습니다. 이것은 동일한 출력을 기대 RANK()하거나 DENSE_RANK()동일한 입력을받는 것과는 아무런 관련이 없습니다. 이것은 SQL Server에 ( ORDER BY절 을 생략하여 ) 순서에 신경 쓰지 않는다고 말했을 때 결정적인 순서를 가정하거나 기대 하는 것입니다. 결과. 여기 # 3을보십시오 :


7

통사론:

WindowFunction() OVER (PARTITION BY <some expressions>        -- partition list
                       ORDER BY <some other expressions>)     -- order list

절의 표현식 이 결정론 적인 한, 함수 RANK()DENSE_RANK()의 정의에 따라 동일한 결과를 생성 할 수 OVER있습니다. 그것이 Itzik Ben-Gun이 그의 기사에서 의미 한 바입니다. 이 목록은 대부분 관련 테이블의 열일뿐입니다.

따라서 함수는 일반적으로 결정적이지는 않지만 파티션 및 순서 목록을 검토 할 때 두 가지 경우를 구별하고 결정적 또는 비 고려로 간주 할 수 있습니다.

제 생각에는 SQL-Server 개발자들이 결정적 함수의 정의와 상반되는 방식에도 불구하고 항상 "비 결정적"으로 구현하기가 더 쉽다는 결론을 내 렸습니다. 따라서 현재 구현에서는 엔진이 항상 비 결정적이라고 간주하기 때문에 MSDN에서는 비 결정적이라고 표시됩니다.

하나 개 더 인수는 다른 두 윈도우 함수는 점이다 ROW_NUMBER()그리고 NTILE()그들이 동일한 출력을 가지고 들어, 목록으로 파티션 순서로 표현 만 결정하지만 독특한뿐만 아니라 할 필요가 있기 때문에, 훨씬 더 복잡합니다. 따라서 이러한 모든 세부 사항을 구현하는 것은 쉽지 않습니다.


Aaron Bertrand가 그의 대답에서 명확하게 설명했듯이 결정론과는 아무런 관련이 없으므로 결과 집합의 순서에 대해서는 언급하지 않을 것입니다.

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