¿Son RANK () y DENSE_RANK () deterministas o no deterministas?

27

Según el oficial Microsoft BOL DENSE_RANK no es determinista ( RANK () ). Pero según las funciones de clasificación de Itzik Ben-Gan "... las funciones RANK () y DENSE_RANK () son siempre deterministas". ¿Quién tiene la razón?

Lo que he encontrado hasta ahora: la definición de Microsoft "Las funciones deterministas siempre devuelven el mismo resultado cada vez que se llaman con un conjunto específico de valores de entrada y se les da el mismo estado de la base de datos".

Entonces, en las tablas de teoría de conjuntos Empleados

Employee            Salary
Sue Right            1.00
Robin Page           1.00
Phil Factor          1.00

y empleados2

Employee            Salary
Phil Factor          1.00
Sue Right            1.00
Robin Page           1.00

son lo mismo. Pero las funciones de Clasificación devuelven valores diferentes:

    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
fuente

Respuestas:

23

Según el oficial Microsoft BOL DENSE_RANK no es determinista (RANK ()). Pero según las funciones de clasificación de Itzik Ben-Gan "... las funciones RANK () y DENSE_RANK () son siempre deterministas". ¿Quién tiene la razón?

Ambos tienen razón, porque están usando diferentes sentidos de la palabra "determinista".

Desde el punto de vista del optimizador de SQL Server, "determinista" tiene un significado muy preciso; un significado que existía antes de que se añadieran funciones de ventana y clasificación al producto. Para el optimizador, la propiedad "determinista" define si una función puede duplicarse libremente dentro de sus estructuras de árbol internas durante la optimización. Esto no es legal para una función no determinista.

Determinista aquí significa: la instancia exacta de la función siempre devuelve la misma salida para la misma entrada, sin importar cuántas veces se llame. Esto nunca es cierto para las funciones de ventanas, por definición, porque como una función escalar (de una fila), no devuelven el mismo resultado dentro de una fila o entre filas. Para decirlo simplemente, usando ROW_NUMBERcomo ejemplo:

La ROW_NUMBERfunción devuelve diferentes valores para diferentes filas (¡por definición!), Por lo que para fines de optimización no es determinista

Este es el sentido que BOL está usando.

Itzik está haciendo un punto diferente sobre el determinismo del resultado como un todo. Sobre un conjunto de entradas ordenadas (con desempate adecuado) la salida es una secuencia "determinista". Esa es una observación válida, pero no es la calidad "determinista" lo que es importante durante la optimización de la consulta.

Paul White dice GoFundMonica
fuente
10

NTILE()es un caso interesante parece aplicarse después de la clasificación (que, en el caso de un empate, se deja a los propios dispositivos de SQL Server, y esto generalmente es impulsado por la elección más eficiente de índice para fines de clasificación). Puede hacer esto determinista al no forzar a SQL Server a hacer una elección arbitraria aquí: agregue uno o más separadores de vínculos a la OVER()cláusula:

OVER (ORDER BY Salary, Employee)

Esencialmente necesita hacer que la clasificación sea única. Si tiene empleados con el mismo nombre, es posible que deba elegir una columna de desempate diferente o seguir agregando columnas hasta que realmente no haya vínculos.

Para RANK()y DENSE_RANK(), los vínculos son en realidad una razón crucial por la que no se pueden obtener valores diferentes. Trate de no confundir el determinismo de la salida de la función con el determinismo del orden de los resultados. Si sus consultas no tienen ORDER BY, entonces, ¿qué no es determinista sobre esto?

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()y DENSE_RANK()aplicó los mismos valores en ambos casos, SQL Server simplemente le devolvió los resultados en un orden diferente. Esto no tiene nada que ver con esperar la misma salida RANK()o DENSE_RANK()recibir la misma entrada: se trata de asumir o esperar un orden determinista cuando le ha dicho a SQL Server (omitiendo una ORDER BYcláusula) que no le importa el orden de Los resultados. Ver # 3 aquí:

Aaron Bertrand
fuente
7

Sintaxis:

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

Se garantiza que ambas funciones RANK()y DENSE_RANK(), por sus definiciones, producen los mismos resultados siempre que las expresiones en la OVERcláusula sean deterministas en sí mismas. Y eso es lo que Itzik Ben-Gun quiso decir en su artículo. Estas listas suelen ser solo columnas de las tablas involucradas.

Entonces, si bien las funciones son generales no son deterministas, su implementación podría haber tenido cuidado de distinguir los dos casos y considerarlos deterministas o no, al examinar las listas de partición y orden.

Mi conjetura es que los desarrolladores de SQL-Server decidieron que era más fácil implementarlos como siempre "no deterministas" a pesar de que esto contradice de alguna manera su definición de funciones deterministas. Por lo tanto, se declaran como no deterministas en MSDN porque en la implementación actual, el motor los considera siempre como no deterministas.

Un argumento más es que las otras dos funciones de ventana, ROW_NUMBER()y NTILE(), son aún más complicadas porque para ellas tienen una salida idéntica, la expresión en la partición y el orden por listas no solo tiene que ser determinista sino también única. Entonces, implementar todos esos detalles está lejos de ser trivial.


No comentaré el orden de los conjuntos de resultados, ya que esto no tiene nada que ver con el determinismo, como Aaron Bertrand ha explicado claramente en su respuesta.

ypercubeᵀᴹ
fuente