Estoy escribiendo en una próxima publicación mía del blog sobre las funciones de clasificación y ventana agregada, específicamente los iteradores de Segmento y Proyecto de secuencia. La forma en que lo entiendo es que Segmento identifica filas en una secuencia que constituyen el final / principio de un grupo, por lo que la siguiente consulta:
SELECT ROW_NUMBER() OVER (PARTITION BY someGroup ORDER BY someOrder)
Utilizará Segmento para saber cuándo una fila pertenece a un grupo diferente que no sea la fila anterior. El iterador del Proyecto de secuencia realiza el cálculo del número de fila real, en función de la salida de la salida del iterador de segmento.
Pero la siguiente consulta, usando esa lógica, no debería tener que incluir un Segmento, porque no hay expresión de partición.
SELECT ROW_NUMBER() OVER (ORDER BY someGroup, someOrder)
Sin embargo, cuando pruebo esta hipótesis, ambas consultas utilizan un operador de segmento. La única diferencia es que la segunda consulta no necesita un GroupBy
en el segmento. ¿No elimina eso la necesidad de un segmento en primer lugar?
Ejemplo
CREATE TABLE dbo.someTable (
someGroup int NOT NULL,
someOrder int NOT NULL,
someValue numeric(8, 2) NOT NULL,
PRIMARY KEY CLUSTERED (someGroup, someOrder)
);
--- Query 1:
SELECT ROW_NUMBER() OVER (PARTITION BY someGroup ORDER BY someOrder)
FROM dbo.someTable;
--- Query 2:
SELECT ROW_NUMBER() OVER (ORDER BY someGroup, someOrder)
FROM dbo.someTable;
fuente
<GroupBy />
por lo que el segmento realmente no hace nada, casi envía la columna del segmento al operador del Proyecto de secuencia. La razón para que el operador del segmento esté allí podría ser que el operador del Proyecto de secuencia necesita ese valor para hacer su trabajo.Respuestas:
Encontré esta publicación de blog de 6 años que menciona el mismo comportamiento.
Parece que
ROW_NUMBER()
siempre incluye un operador de segmento,PARTITION BY
se use o no. Si tuviera que adivinar, diría que esto se debe a que facilita la creación de un plan de consulta en el motor.Si el segmento se necesita en la mayoría de los casos, y en los casos en que no se necesita es esencialmente una no operación de costo cero, es mucho más simple incluirlo siempre en el plan cuando se utiliza una función de ventana.
fuente
De acuerdo con el showplan.xsd para el plan de ejecución,
GroupBy
aparece sinminOccurs
omaxOccurs
atributos que, por lo tanto, predeterminan a [1..1] haciendo que el elemento sea obligatorio, no necesariamente contenido. El elemento secundarioColumnReference
de tipo (ColumnReferenceType
) tieneminOccurs
0 ymaxOccurs
[0 .. *] ilimitado, lo que lo hace opcional , de ahí el elemento vacío permitido. Si intenta eliminar manualmenteGroupBy
y forzar el plan, obtendrá el error esperado:Curiosamente, descubrí que puede eliminar manualmente el operador Segmento para obtener un plan válido para forzar que se ve así:
Sin embargo, cuando ejecuta con ese plan (usando
OPTION ( USE PLAN ... )
), el Operador de Segmento reaparece mágicamente. Solo muestra que el optimizador solo toma los planes XML como una guía aproximada.Mi plataforma de prueba:
Recorte el plan XML del equipo de prueba y guárdelo como un plan .sql para ver el plan menos el segmento.
PD: No pasaría demasiado tiempo cortando planes SQL manualmente, como si supieras que lo sabrías, lo considero como un trabajo ocupado que consume mucho tiempo y algo que nunca haría. Oh espera !? :)
fuente