¿Por qué la variable de la tabla está obligando a una exploración de índice mientras que la tabla TEMP utiliza búsqueda y búsqueda de marcadores?

dba.stackexchange https://dba.stackexchange.com/questions/108352

Pregunta

Estoy tratando de entender por qué usar una variable de tabla está impidiendo que el optimizador use un índice de búsqueda y luego la búsqueda de marcadores versus una exploración de índice.

Poblando la tabla:

CREATE TABLE dbo.Test 
(
    RowKey INT NOT NULL PRIMARY KEY, 
    SecondColumn CHAR(1) NOT NULL DEFAULT 'x',
    ForeignKey INT NOT NULL 
) 

INSERT dbo.Test 
(
    RowKey, 
    ForeignKey
) 
SELECT TOP 1000000 
    ROW_NUMBER() OVER (ORDER BY (SELECT 0)),
    ABS(CHECKSUM(NEWID()) % 10)     
FROM sys.all_objects s1
CROSS JOIN sys.all_objects s2 

CREATE INDEX ix_Test_1 ON dbo.Test (ForeignKey) 

Pover una variable de tabla con un solo registro e intento de buscar la clave principal y la segunda columna buscando en la columna de clave externa:

DECLARE @Keys TABLE (RowKey INT NOT NULL) 

INSERT @Keys (RowKey) VALUES (10)

SELECT 
    t.RowKey,
    t.SecondColumn
FROM
    dbo.Test t 
INNER JOIN 
    @Keys k
ON
    t.ForeignKey = k.RowKey

a continuación es el plan de ejecución:

 ingrese la descripción de la imagen aquí

Ahora la misma consulta con una tabla TEMP en lugar de:

CREATE TABLE #Keys (RowKey INT NOT NULL) 

INSERT #Keys (RowKey) VALUES (10) 

SELECT 
    t.RowKey,
    t.SecondColumn
FROM
    dbo.Test t 
INNER JOIN 
    #Keys k
ON
    t.ForeignKey = k.RowKey

Este plan de consulta utiliza una búsqueda de búsqueda y marcador:

 ingrese la descripción de la imagen aquí

¿Por qué el optimizador está dispuesto a hacer la búsqueda del marcador con la tabla TEMP, pero no la variable de la tabla?

La variable de tabla se usa en este ejemplo para representar datos que vienen a través de un tipo de tabla definido por el usuario en un procedimiento almacenado.

Me doy cuenta de que la búsqueda del índice podría no ser apropiada si el valor clave de la clave externa se produjo cientos de miles de veces. En ese caso, un escaneo probablemente sería una mejor opción. Para el escenario que creé, no había ninguna fila con un valor de 10. Todavía creo que el comportamiento es interesante y quisiera saber si hay una razón para ello.

Fiddle SQL

Agregar OPTION (RECOMPILE) no cambió el comportamiento. El UDDT tiene una clave principal.

@@VERSION es SQL Server 2008 R2 (SP2) - 10.50.4042.0 (x64) (Build 7601: Paquete de servicio 1) (hipervisor)

¿Fue útil?

Solución

El motivo del comportamiento es que SQL Server no puede determinar la cantidad de filas que coincidirán con forsignKey, ya que no hay ningún índice con Rowkey como la columna líder (puede deducir esto de las estadísticas en la tabla #Temp, pero aquellas No exista para variables de tabla / UDTTS), por lo que hace una estimación de 100,000 filas, que se maneja mejor con un escaneo que una búsqueda de búsqueda +. En el momento en que SQL Server se da cuenta de que solo hay una fila, es demasiado tarde.

Es posible que pueda construir su UDTT de manera diferente; En versiones más modernas de SQL Server, puede crear índices secundarios en variables de tabla, pero esta sintaxis no está disponible en 2008 R2.

Por cierto, puede obtener el comportamiento de búsqueda (al menos en mis ensayos limitados) si intenta evitar el mapa de bits / sonda al insinuar un buceo anidado. Únete:

DECLARE @Keys TABLE (RowKey INT PRIMARY KEY); -- can't hurt

INSERT @Keys (RowKey) VALUES (10);

SELECT 
     t.RowKey
    ,t.SecondColumn
FROM
    dbo.Test t 
INNER JOIN 
    @Keys k
ON
    t.ForeignKey = k.RowKey
    OPTION (LOOP JOIN);

i Aprendí este truco de Paul White hace varios años. Por supuesto, debe tener cuidado de poner cualquier tipo de sugerencias de unirse en el código de producción, esto puede fallar si las personas realizan cambios en los objetos subyacentes y que el tipo específico de unión ya no es posible o ya no es más óptimo.

Para consultas más complejas, y cuando se muda a SQL Server 2012 o superior, es posible que la bandera de rastreo 2453 podría ayudar. Sin embargo, esa bandera no ayudó con este simple unión. Y se aplicarían las mismas exenciones de responsabilidad: esto es solo una cosa alternativa que generalmente no debería hacer sin una tonelada de documentación y procedimientos de prueba de regresión rigurosos en su lugar.

Además, el Service Pack 1 está fuera de apoyo, debe obtener en Service Pack 3 + ms15-058 .

Otros consejos

Las variables de tabla y las tablas TEMP se manejan de manera diferente de varias maneras.Hay una genialResponda aquí con muchos específicos en cuanto a donde son diferentes.

Específicamente en su caso, supongo que el hecho de que las tablas TEMP puedan tener estadísticas adicionales generadas y planes paralelos, mientras que las variables de la tabla tienen estadísticas más limitadas (sin estadísticas de nivel de columna) y ningún plan paralelo es su culpable.

Es posible que esté mejor que esté mejorando la variable de la tabla en una tabla TEMP durante la duración del procedimiento almacenado.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a dba.stackexchange
scroll top