sql >> Base de Datos >  >> RDS >> Database

USAR SUGERENCIA y DISABLE_OPTIMIZED_NESTED_LOOP

Uno de los algoritmos disponibles para unir dos tablas en SQL Server es Nested Loops. La combinación de bucles anidados utiliza una entrada de combinación como tabla de entrada externa y otra como tabla de entrada interna. El ciclo externo itera la tabla de entrada externa fila por fila. El ciclo interno, ejecutado para cada fila externa, busca filas coincidentes en la tabla de entrada interna.

Esto se llama unión de bucles anidados ingenuos.

Si tiene un índice sobre las condiciones de combinación en la tabla de entrada interna, no es necesario realizar un ciclo interno para cada fila de la tabla externa. En su lugar, puede pasar el valor de la tabla externa como argumento de búsqueda y conectar todas las filas devueltas de la tabla interna a las filas de la tabla externa.

La búsqueda por la tabla interior es un acceso aleatorio. SQL Server, a partir de la versión 2005, tiene la optimización de clasificación por lotes (no confundir con el operador de clasificación en modo por lotes para índices de almacén de columnas). El propósito de la optimización es ordenar claves de búsqueda de la tabla externa antes de obtener datos de la interna. Así, un acceso aleatorio será secuencial.

El plan de ejecución no muestra la operación de clasificación por lotes como un operador separado. En su lugar, puede ver la propiedad Optimized=true en el operador Nested Loops. Si fuera posible ver la ordenación por lotes como un operador separado en el plan, se vería así:

En este pseudoplan, leemos datos del índice ix_CustomerID no agrupado en el orden de esta clave de índice CustomerID. Luego, debemos realizar una búsqueda de clave en el índice agrupado, ya que ix_CustomerID no es un índice de cobertura. Key Lookup es una operación de búsqueda de clave de índice agrupado:un acceso aleatorio. Para que sea secuencial, SQL Server puede ejecutar la ordenación por lotes mediante la clave de índice agrupado.

Para obtener más información sobre la ordenación por lotes, consulte mi artículo Ordenación por lotes y bucles anidados.

Esta optimización proporciona un gran impulso con un número suficiente de filas. Puede leer más sobre los resultados de sus pruebas en el blog Uniones de bucles anidados OPTIMIZADOS, creado por Craig Freedman, un desarrollador de optimizadores.

Sin embargo, si la cantidad real de filas es menor que la esperada, los costos adicionales de CPU para construir este tipo pueden ocultar sus beneficios, aumentar el consumo de CPU y reducir su rendimiento.

Considere este ejemplo particular:

use tempdb;
go
-- create a test table (SalesOrderID - clustered PK)
create table dbo.SalesOrder(SalesOrderID int identity primary key, CustomerID int not null, SomeData char(200) not null);
go
-- add test data
with n as (select top(1000000) rn = row_number() over(order by (select null)) from sys.all_columns c1,sys.all_columns c2)
insert dbo.SalesOrder(CustomerID, SomeData) select rn%500000, str(rn,100) from n;
-- create a clustered index
create index ix_c on dbo.Salesorder(CustomerID);
go
-- the batch sort optimization is enabled by default (Nested Loops: Optimized = true)
select * from dbo.SalesOrder with(index(ix_c)) where CustomerID < 1000;
-- disable it with the DISABLE_OPTIMIZED_NESTED_LOOP hint (Nested Loops: Optimized = false)
select * from dbo.SalesOrder with(index(ix_c)) where CustomerID < 1000 option(use hint('DISABLE_OPTIMIZED_NESTED_LOOP'));
go

El resultado devuelto:

Me gustaría llamar su atención sobre el diferente orden de las filas en la salida. El servidor devuelve las filas en el orden en que las procesa, ya que no hemos especificado explícitamente ORDER BY. En el primer caso, leemos gradualmente del índice ix_c. Sin embargo, para optimizar las lecturas aleatorias del índice agrupado, filtramos las filas por la clave del índice SalesOrderID agrupado. En el segundo caso, no hay clasificación, y las lecturas se realizan en el orden clave de CustomerID del índice no agrupado ix_c.

Diferencia con el indicador de seguimiento 2340

A pesar de que la documentación especifica el indicador de seguimiento 2340 como un equivalente de la sugerencia DISABLE_OPTIMIZED_NESTED_LOOP, en realidad no es cierto.

Considere el siguiente ejemplo en el que usaré el comando ACTUALIZAR ESTADÍSTICAS... CON CUENTAPÁGINAS para engañar al optimizador diciendo que la tabla ocupa más páginas de las que realmente tiene. Luego, eche un vistazo a estas consultas:

  1. Sin pistas (he agregado MAXDOP para mantener un plan simple);
  2. Con la sugerencia DISABLE_OPTIMIZED_NESTED_LOOP;
  3. Con la marca de rastreo 2340.
-- create a huge table
update statistics dbo.SalesOrder with pagecount = 100000;
go
set showplan_xml on;
go
-- 1. without hints
select * from dbo.SalesOrder with(index(ix_c)) where CustomerID < 1000000 option(maxdop 1);
-- 2. hint
select * from dbo.SalesOrder with(index(ix_c)) where CustomerID < 1000000 option(use hint('DISABLE_OPTIMIZED_NESTED_LOOP'), maxdop 1);
-- 3. trace flag
select * from dbo.SalesOrder with(index(ix_c)) where CustomerID < 1000000 option(querytraceon 2340, maxdop 1);
go
set showplan_xml off;
go

Como resultado, tenemos los siguientes planes:

Nested Loops tiene la propiedad Optimized =false en los tres planes. El hecho es que al aumentar el ancho de la tabla, también aumentamos el costo de acceso a los datos. Cuando el costo es lo suficientemente alto, SQL Server puede usar el operador Ordenar explícito, en lugar del operador Ordenar por lotes implícito. Podemos ver esto en el primer plan de consulta.

En la segunda consulta, usamos la sugerencia DISABLE_OPTIMIZED_NESTED_LOOP que desactiva la clasificación por lotes implícita. Sin embargo, elimina una clasificación explícita por un operador separado.

En el tercer plan, podemos ver que a pesar de agregar el indicador de rastreo 2340, el operador de clasificación existe.

Por lo tanto, la diferencia entre la sugerencia y la bandera es la siguiente:una sugerencia deshabilita la optimización al transformar un acceso aleatorio en uno en serie, dependiendo de si el servidor lo implementa con el ordenamiento por lotes implícito o con el operador Ordenar por separado.

PD Los planes pueden depender del equipo. Por lo tanto, si no puede ejecutar estas consultas, intente aumentar o disminuir el tamaño de la columna SomeData char(200) en la descripción de la tabla dbo.SalesOrder.

El artículo fue traducido por el equipo de Codingsight con el permiso del autor.