RANK () et DENSE_RANK () sont-ils déterministes ou non déterministes?

27

Selon le responsable Microsoft, BOL DENSE_RANK n'est pas déterministe ( RANK () ). Mais selon les fonctions de classement d'Itzik Ben-Gan "... les fonctions RANK () et DENSE_RANK () sont toujours déterministes". Qui a raison?

Ce que j'ai trouvé jusqu'à présent: Définition de Microsoft "Les fonctions déterministes renvoient toujours le même résultat chaque fois qu'elles sont appelées avec un ensemble spécifique de valeurs d'entrée et avec le même état de la base de données."

Donc, dans les tables théoriques Set Employés

Employee            Salary
Sue Right            1.00
Robin Page           1.00
Phil Factor          1.00

et employés2

Employee            Salary
Phil Factor          1.00
Sue Right            1.00
Robin Page           1.00

sont identiques. Mais les fonctions de classement renvoient des valeurs différentes:

    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
la source

Réponses:

23

Selon le responsable Microsoft, BOL DENSE_RANK n'est pas déterministe (RANK ()). Mais selon les fonctions de classement d'Itzik Ben-Gan "... les fonctions RANK () et DENSE_RANK () sont toujours déterministes". Qui a raison?

Ils ont tous les deux raison, car ils utilisent différents sens du mot "déterministe".

Du point de vue de l'optimiseur SQL Server, «déterministe» a une signification très précise; une signification qui existait avant l'ajout de fonctions de fenêtre et de classement au produit. Pour l'optimiseur, la propriété "déterministe" définit si une fonction peut être librement dupliquée dans ses arborescences internes pendant l'optimisation. Ce n'est pas légal pour une fonction non déterministe.

Déterministe signifie ici: l'instance exacte de la fonction renvoie toujours la même sortie pour la même entrée, quel que soit le nombre de fois où elle est appelée. Cela n'est jamais vrai pour les fonctions de fenêtrage, par définition, car en tant que fonction scalaire (à une seule ligne), elles ne renvoient pas le même résultat sur une ligne ou sur plusieurs lignes. Pour le dire simplement, en utilisant ROW_NUMBERcomme exemple:

La ROW_NUMBERfonction renvoie des valeurs différentes pour différentes lignes (par définition!), Donc à des fins d'optimisation, elle n'est pas déterministe

C'est le sens que BOL utilise.

Itzik fait un point différent sur le déterminisme du résultat dans son ensemble. Sur un ensemble d'entrées ordonné (avec un bris d'égalité approprié), la sortie est une séquence "déterministe". C'est une observation valable, mais ce n'est pas la qualité "déterministe" qui est importante lors de l'optimisation des requêtes.

Paul White dit GoFundMonica
la source
10

NTILE()est un cas intéressant; il semble s'appliquer après le tri (qui, dans le cas d'une égalité, est laissé aux propres périphériques de SQL Server, et cela est généralement déterminé par le choix d'index le plus efficace à des fins de tri). Vous pouvez rendre cela déterministe en ne forçant pas SQL Server à faire un choix arbitraire ici - ajoutez un ou plusieurs bris d'égalité à la OVER()clause:

OVER (ORDER BY Salary, Employee)

Essentiellement, vous devez rendre le tri unique. Si vous avez des employés du même nom, vous devrez peut-être choisir une autre colonne de départage ou continuer à ajouter des colonnes jusqu'à ce qu'il ne puisse plus y avoir de lien.

Pour RANK()et DENSE_RANK(), les liens sont en fait une raison cruciale pour laquelle vous ne pouvez pas obtenir de valeurs différentes. Essayez de ne pas confondre le déterminisme de la sortie de la fonction avec le déterminisme de l'ordre des résultats. Si vos requêtes n'ont pas ORDER BY, alors qu'est-ce qui n'est pas déterministe à ce sujet?

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()et DENSE_RANK()appliqué les mêmes valeurs dans les deux cas, SQL Server vient de vous renvoyer les résultats dans un ordre différent. Cela n'a rien à voir avec l'attente de la même sortie RANK()ou DENSE_RANK()la même entrée - il s'agit simplement de supposer ou d'attendre un ordre déterministe lorsque vous avez dit à SQL Server (en omettant une ORDER BYclause) que vous ne vous souciez pas de l'ordre de Les resultats. Voir # 3 ici:

Aaron Bertrand
la source
7

Syntaxe:

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

Les deux fonctions, RANK()et DENSE_RANK(), par leurs définitions, sont garanties de produire les mêmes résultats tant que les expressions de la OVERclause sont elles-mêmes déterministes. Et c'est ce qu'Itzik Ben-Gun voulait dire dans son article. Ces listes ne sont le plus souvent que des colonnes des tables concernées.

Ainsi, alors que les fonctions sont générales ne sont pas déterministes, leur implémentation aurait pu prendre soin de distinguer les deux cas et de les considérer déterministes ou non, lors de l'examen de la partition et des listes de commandes.

Ma conjecture est que les développeurs SQL-Server ont décidé qu'il était plus facile de les implémenter comme toujours "non déterministes" malgré que cela contredise en quelque sorte leur définition des fonctions déterministes. Ainsi, ils sont déclarés comme non déterministes dans MSDN car dans l'implémentation actuelle, le moteur les considère toujours comme non déterministes.

Un autre argument est que les deux autres fonctions de fenêtre, ROW_NUMBER()et NTILE(), sont encore plus compliquées car pour elles ayant une sortie identique, l'expression dans la partition et l'ordre par listes doivent non seulement être déterministes mais aussi uniques. La mise en œuvre de tous ces détails est donc loin d'être anodine.


Je ne commenterai pas l'ordre des ensembles de résultats, car cela n'a rien à voir avec le déterminisme, comme Aaron Bertrand l'a clairement expliqué dans sa réponse.

ypercubeᵀᴹ
la source