Sind RANK () und DENSE_RANK () deterministisch oder nicht deterministisch?

27

Laut offiziellem Microsoft BOL ist DENSE_RANK nicht deterministisch ( RANK () ). Nach den Ranglistenfunktionen von Itzik Ben-Gan "... sind die Funktionen RANK () und DENSE_RANK () immer deterministisch". Wer hat Recht?

Was ich bisher gefunden habe: Microsoft Definition "Deterministische Funktionen geben immer das gleiche Ergebnis zurück, wenn sie mit einem bestimmten Satz von Eingabewerten aufgerufen werden und den gleichen Status der Datenbank haben."

Also in Set Theorie Tabellen Mitarbeiter

Employee            Salary
Sue Right            1.00
Robin Page           1.00
Phil Factor          1.00

und Mitarbeiter2

Employee            Salary
Phil Factor          1.00
Sue Right            1.00
Robin Page           1.00

sind gleich. Ranking-Funktionen geben jedoch unterschiedliche Werte zurück:

    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
Pavel Nefyodov
quelle

Antworten:

23

Laut offiziellem Microsoft BOL ist DENSE_RANK nicht deterministisch (RANK ()). Nach den Ranglistenfunktionen von Itzik Ben-Gan "... sind die Funktionen RANK () und DENSE_RANK () immer deterministisch". Wer hat Recht?

Sie haben beide Recht, weil sie verschiedene Sinne des Wortes "deterministisch" verwenden.

Aus Sicht des SQL Server-Optimierers hat "deterministisch" eine sehr genaue Bedeutung. Eine Bedeutung, die existierte, bevor Fenster- und Ranglistenfunktionen zum Produkt hinzugefügt wurden. Für den Optimierer definiert die Eigenschaft "deterministisch", ob eine Funktion während der Optimierung innerhalb ihrer internen Baumstrukturen frei dupliziert werden kann. Dies ist für eine nicht deterministische Funktion nicht zulässig.

Deterministisch bedeutet hier: Die exakte Instanz der Funktion gibt immer dieselbe Ausgabe für dieselbe Eingabe zurück, unabhängig davon, wie oft sie aufgerufen wird. Dies gilt per Definition nie für Fensterfunktionen, da sie als (einzeilige) Skalarfunktion nicht das gleiche Ergebnis innerhalb einer Zeile oder über mehrere Zeilen hinweg zurückgeben. Einfach ausgedrückt am ROW_NUMBERBeispiel:

Die ROW_NUMBERFunktion gibt verschiedene Werte für verschiedene Zeilen zurück (per Definition!), Daher ist sie zu Optimierungszwecken nicht deterministisch

Dies ist der Sinn, den BOL verwendet.

Itzik macht einen anderen Punkt in Bezug auf den Determinismus des Gesamtergebnisses. Über einen geordneten Eingabesatz (mit geeignetem Gleichstand) ist die Ausgabe eine "deterministische" Sequenz. Dies ist eine gültige Beobachtung, aber es ist nicht die "deterministische" Qualität, die bei der Abfrageoptimierung wichtig ist.

Paul White sagt GoFundMonica
quelle
10

NTILE()ist ein interessanter Fall; Es scheint nach dem Sortieren zuzutreffen (was im Falle einer Unentschiedenheit den SQL Server-eigenen Geräten überlassen bleibt und in der Regel von der effizientesten Auswahl des Index für Sortierzwecke abhängt). Sie können dies deterministisch machen, indem Sie SQL Server hier nicht zu einer willkürlichen Auswahl zwingen - fügen Sie der OVER()Klausel einen oder mehrere Unterbrecher hinzu :

OVER (ORDER BY Salary, Employee)

Grundsätzlich müssen Sie die Sortierung eindeutig gestalten. Wenn Sie Mitarbeiter mit demselben Namen haben, müssen Sie möglicherweise eine andere Trennsäule auswählen oder weitere Spalten hinzufügen, bis es wirklich keine Verbindungen mehr gibt.

Für RANK()und DENSE_RANK()sind Bindungen ein entscheidender Grund dafür, dass man keine unterschiedlichen Werte erhalten kann. Versuchen Sie, den Determinismus der Ausgabe der Funktion nicht mit dem Determinismus der Reihenfolge der Ergebnisse zu verwechseln. Wenn Ihre Abfragen nicht vorhanden sind ORDER BY, was ist dann nicht deterministisch?

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()und DENSE_RANK()in beiden Fällen dieselben Werte angewendet, hat SQL Server die Ergebnisse in einer anderen Reihenfolge an Sie zurückgegeben. Dies hat nichts damit zu tun, dieselbe Ausgabe von derselben Eingabe zu erwarten RANK()oder DENSE_RANK()dieselbe Eingabe zu erhalten - es geht lediglich darum, eine deterministische Reihenfolge anzunehmen oder zu erwarten, wenn Sie SQL Server mitgeteilt haben (indem Sie eine ORDER BYKlausel weglassen ), dass Sie sich nicht für die Reihenfolge von interessieren die Ergebnisse. Siehe # 3 hier:

Aaron Bertrand
quelle
7

Syntax:

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

Beide Funktionen RANK()und DENSE_RANK()liefern nach ihrer Definition garantiert die gleichen Ergebnisse, solange die Ausdrücke in der OVERKlausel selbst deterministisch sind. Und genau das meinte Itzik Ben-Gun in seinem Artikel. Diese Listen sind meist nur Spalten der betroffenen Tabellen.

Obwohl die Funktionen allgemein nicht deterministisch sind, hätte ihre Implementierung bei der Prüfung der Partitions- und Ordnungslisten dafür sorgen können, dass die beiden Fälle voneinander unterschieden und als deterministisch eingestuft wurden oder nicht.

Meine wilde Vermutung ist, dass die SQL-Server-Entwickler entschieden haben, dass es einfacher ist, sie als immer "nicht deterministisch" zu implementieren, obwohl dies in gewisser Weise ihrer Definition deterministischer Funktionen widerspricht. Daher werden sie in MSDN als nicht deterministisch angegeben, da sie in der aktuellen Implementierung von der Engine immer als nicht deterministisch betrachtet werden.

Ein weiteres Argument ist , dass die beiden anderen Fensterfunktionen, ROW_NUMBER()und NTILE()werden noch komplizierter , weil für sie identisch Ausgang, der Ausdruck in der Partition und Reihenfolge von Listen nicht nur deterministisch sein, aber einzigartig als auch. Die Implementierung all dieser Details ist also alles andere als trivial.


Ich werde die Reihenfolge der Ergebnismengen nicht kommentieren, da dies nichts mit dem Determinismus zu tun hat, wie Aaron Bertrand in seiner Antwort klar erklärt hat.

ypercubeᵀᴹ
quelle