RANK()とDENSE_RANK()は確定的ですか、非確定的ですか?


27

公式のMicrosoft BOLによると、DENSE_RANKは非決定的です(RANK())。しかし、Itzik Ben-Ganによるランキング関数によると 、「... RANK()およびDENSE_RANK()関数は常に決定論的です」。誰が正しい?

私がこれまでに見つけたもの: Microsoftの定義「特定の入力値セットで呼び出され、データベースの同じ状態が与えられると、決定論関数は常に同じ結果を返します。」

したがって、集合論の表では従業員

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に任意の選択を強制しないことで、この決定性を実現できます。1つ以上のタイブレーカーを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 Serverは結果を異なる順序で返しました。これは、同じ入力からの同じ出力を期待し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句の式自体が決定論的である限り、同じ結果を生成することが保証されています。そして、それがイツィク・ベンガンの記事での意味です。これらのリストは、ほとんどの場合、関係するテーブルの列です。

そのため、関数は一般的ではありませんが、その実装では、パーティションと順序のリストを調べる際に、2つのケースを区別し、それらを決定的であるかどうかを考慮する必要があります。

私の予想では、SQL-Server開発者は、決定論的関数の定義に矛盾があるにもかかわらず、常に「非決定論的」として実装する方が簡単だと判断しました。そのため、現在の実装ではエンジンはそれらを常に非決定的であると見なしているため、MSDNで非決定的であると述べられています。

もう1つの引数は、他の2つのウィンドウ関数、ROW_NUMBER()およびNTILE()がさらに複雑であるということです。これらの関数は、出力が同一であるため、パーティション内の式と順序によるリストが決定的であるだけでなく、一意である必要があるためです。したがって、これらすべての詳細を実装するのは簡単なことではありません。


アーロン・バートランドが彼の答えで明確に説明しているように、これは決定論とは何の関係もないので、結果セットの順序についてはコメントしません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.