Como las otras respuestas ya indican, SQL Server puede o no garantizar explícitamente que las filas se ordenen en orden de índice agrupado antes de insert
.
Esto depende de si el operador de índice agrupado en el plan tiene o no el DMLRequestSort
conjunto de propiedades (que a su vez depende del número estimado de filas que se insertan).
Si encuentra que SQL Server está subestimando esto por cualquier razón, podría beneficiarse al agregar un mensaje explícito ORDER BY
a la SELECT
consulta para minimizar las divisiones de página y la consiguiente fragmentación de la INSERT
operación
Ejemplo:
use tempdb;
GO
CREATE TABLE T(N INT PRIMARY KEY,Filler char(2000))
CREATE TABLE T2(N INT PRIMARY KEY,Filler char(2000))
GO
DECLARE @T TABLE (U UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID(),N int)
INSERT INTO @T(N)
SELECT number
FROM master..spt_values
WHERE type = 'P' AND number BETWEEN 0 AND 499
/*Estimated row count wrong as inserting from table variable*/
INSERT INTO T(N)
SELECT T1.N*1000 + T2.N
FROM @T T1, @T T2
/*Same operation using explicit sort*/
INSERT INTO T2(N)
SELECT T1.N*1000 + T2.N
FROM @T T1, @T T2
ORDER BY T1.N*1000 + T2.N
SELECT avg_fragmentation_in_percent,
fragment_count,
page_count,
avg_page_space_used_in_percent,
record_count
FROM sys.dm_db_index_physical_stats(2, OBJECT_ID('T'), NULL, NULL, 'DETAILED')
;
SELECT avg_fragmentation_in_percent,
fragment_count,
page_count,
avg_page_space_used_in_percent,
record_count
FROM sys.dm_db_index_physical_stats(2, OBJECT_ID('T2'), NULL, NULL, 'DETAILED')
;
Muestra que T
está masivamente fragmentado
avg_fragmentation_in_percent fragment_count page_count avg_page_space_used_in_percent record_count
---------------------------- -------------------- -------------------- ------------------------------ --------------------
99.3116118225536 92535 92535 67.1668272794663 250000
99.5 200 200 74.2868173956017 92535
0 1 1 32.0978502594514 200
Pero para la T2
fragmentación es mínima
avg_fragmentation_in_percent fragment_count page_count avg_page_space_used_in_percent record_count
---------------------------- -------------------- -------------------- ------------------------------ --------------------
0.376 262 62500 99.456387447492 250000
2.1551724137931 232 232 43.2438349394613 62500
0 1 1 37.2374598468001 232
Por el contrario, a veces es posible que desee forzar a SQL Server a subestimar el recuento de filas cuando sepa que los datos ya están ordenados previamente y desee evitar una clasificación innecesaria. Un ejemplo notable es cuando se inserta una gran cantidad de filas en una tabla con una newsequentialid
clave de índice agrupada. En las versiones de SQL Server anteriores a Denali, SQL Server agrega una operación de clasificación innecesaria y potencialmente costosa . Esto se puede evitar con
DECLARE @var INT =2147483647
INSERT INTO Foo
SELECT TOP (@var) *
FROM Bar
Luego, SQL Server estimará que se insertarán 100 filas independientemente del tamaño del Bar
cual esté por debajo del umbral en el que se agrega una clasificación al plan. Sin embargo, como se señala en los comentarios a continuación, esto significa que, por desgracia, la inserción no podrá aprovechar el registro mínimo.
Si el optimizador decide que sería más eficiente clasificar los datos antes de insertarlos, lo hará en algún lugar aguas arriba del operador de inserción. Si introduce una ordenación como parte de su consulta, el optimizador debe darse cuenta de que los datos ya están ordenados y omitir hacerlo nuevamente. Tenga en cuenta que el plan de ejecución elegido puede variar de una ejecución a otra dependiendo del número de filas insertadas en su tabla de etapas.
Si puede capturar planes de ejecución del proceso con y sin el orden explícito, adjúntelos a su pregunta para hacer comentarios.
Editar: 2011-10-28 17:00
La respuesta de @Gonsalu parece mostrar que siempre ocurre una operación de clasificación, este no es el caso. ¡Se requieren guiones de demostración!
Como los guiones se estaban haciendo bastante grandes, los moví a Gist . Para facilitar la experimentación, los scripts usan el modo SQLCMD. Las pruebas se ejecutan en 2K5SP3, doble núcleo, 8 GB.
Las pruebas de inserción cubren tres escenarios:
Primera ejecución, insertando 25 filas.
Los tres planes de ejecución son iguales, no se produce ningún orden en ninguna parte del plan y el análisis de índice agrupado es "ordenado = falso".
Segunda ejecución, insertando 26 filas.
Esta vez los planes difieren.
Por lo tanto, hay un punto de inflexión en el que el optimizador considera que un tipo es necesario. Como muestra @MartinSmith, esto parece basarse en las filas estimadas que se insertarán. En mi plataforma de prueba 25 no requiere un tipo, 26 sí (2K5SP3, doble núcleo, 8 GB)
El script SQLCMD incluye variables que permiten cambiar el tamaño de las filas en la tabla (alterando la densidad de la página) y el número de filas en dbo.MyTable antes de las inserciones adicionales. Según mis pruebas, ninguno tiene ningún efecto en el punto de inflexión.
Si algún lector está tan inclinado, ejecute los scripts y agregue su punto de inflexión como comentario. Interesado saber si varía entre plataformas de prueba y / o versiones.
Editar: 2011-10-28 20:15
Pruebas repetidas en el mismo equipo pero con 2K8R2. Esta vez el punto de inflexión es de 251 filas. Nuevamente, variar la densidad de la página y los recuentos de filas existentes no tiene ningún efecto.
fuente
La
ORDER BY
cláusula en laSELECT
declaración es redundante.Es redundante porque las filas que se insertarán, si es necesario ordenarlas , se ordenan de todos modos.
Vamos a crear un caso de prueba.
Habilitemos la visualización de texto de los planes de consulta reales, para que podamos ver qué tareas lleva a cabo el procesador de consultas.
Ahora, vamos a
INSERT
2K filas en la tabla sin unaORDER BY
cláusula.El plan de ejecución real para esta consulta es el siguiente.
Como puede ver, hay un operador Ordenar antes de que ocurra el INSERT real.
Ahora, limpiemos la tabla y
INSERT
2k filas en la tabla con laORDER BY
cláusula.El plan de ejecución real para esta consulta es el siguiente.
Tenga en cuenta que es el mismo plan de ejecución que se utilizó para la
INSERT
declaración sin laORDER BY
cláusula.Ahora, la
Sort
operación no siempre es necesaria, como Mark Smith ha mostrado en otra respuesta (si el número de filas a insertar es bajo), pero laORDER BY
cláusula sigue siendo redundante en ese caso, porque incluso con una operación explícitaORDER BY
, noSort
se genera ninguna operación por el procesador de consultas.Puede optimizar una
INSERT
declaración en una tabla con un índice agrupado, utilizando un registro mínimoINSERT
, pero eso está fuera del alcance de esta pregunta.Actualizado el 2011-11-02: Como Mark Smith ha demostrado ,
INSERT
es posible que no siempre sea necesario ordenar losORDER BY
mensajes s en una tabla con un índice agrupado ; sin embargo, la cláusula también es redundante en ese caso.fuente