Me doy cuenta de que cuando hay eventos de derrame a tempdb (que causan consultas lentas), a menudo las estimaciones de fila están muy lejos para una unión en particular. He visto que se producen eventos de derrame con combinaciones de combinación y hash y, a menudo, aumentan el tiempo de ejecución de 3x a 10x. Esta pregunta se refiere a cómo mejorar las estimaciones de filas bajo el supuesto de que reducirá las posibilidades de eventos de derrames.
Número real de filas 40k.
Para esta consulta, el plan muestra una estimación de filas incorrectas (11.3 filas):
select Value
from Oav.ValueArray
where ObjectId = (select convert(bigint, Value) NodeId
from Oav.ValueArray
where PropertyId = 3331
and ObjectId = 3540233
and Sequence = 2)
and PropertyId = 2840
option (recompile);
Para esta consulta, el plan muestra una buena estimación de filas (56k filas):
declare @a bigint = (select convert(bigint, Value) NodeId
from Oav.ValueArray
where PropertyId = 3331
and ObjectId = 3540233
and Sequence = 2);
select Value
from Oav.ValueArray
where ObjectId = @a
and PropertyId = 2840
option (recompile);
¿Se pueden agregar estadísticas o sugerencias para mejorar las estimaciones de filas para el primer caso? Intenté agregar estadísticas con valores de filtro particulares (propiedad = 2840) pero no pude obtener la combinación correcta o tal vez se está ignorando porque el ObjectId es desconocido en el momento de la compilación y podría estar eligiendo un promedio sobre todos los ObjectIds.
¿Hay algún modo en el que primero haga la consulta de la sonda y luego la use para determinar las estimaciones de fila o debe volar a ciegas?
Esta propiedad particular tiene muchos valores (40k) en algunos objetos y cero en la gran mayoría. Estaría contento con una pista donde se podría especificar el número máximo esperado de filas para una unión determinada. Este es un problema generalmente inquietante porque algunos parámetros pueden determinarse dinámicamente como parte de la unión o estarían mejor ubicados dentro de una vista (no se admiten variables).
¿Hay algún parámetro que pueda ajustarse para minimizar la posibilidad de derrames en tempdb (por ejemplo, memoria mínima por consulta)? El plan robusto no tuvo efecto en la estimación.
Editar 2013.11.06 : Respuesta a comentarios e información adicional:
Aquí están las imágenes del plan de consulta. Las advertencias son sobre el predicado cardinalidad / búsqueda con el convert ():
Según el comentario de @Aaron Bertrand, intenté reemplazar el convert () como prueba:
create table Oav.SeekObject (
LookupId bigint not null primary key,
ObjectId bigint not null
);
insert into Oav.SeekObject (
LookupId, ObjectId
) VALUES (
1, 3540233
)
select Value
from Oav.ValueArray
where ObjectId = (select ObjectId
from Oav.SeekObject
where LookupId = 1)
and PropertyId = 2840
option (recompile);
Como un punto de interés extraño pero exitoso, también le permitió cortocircuitar la búsqueda:
select Value
from Oav.ValueArray
where ObjectId = (select ObjectId
from Oav.ValueArray
where PropertyId = 2840
and ObjectId = 3540233
and Sequence = 2)
and PropertyId = 2840
option (recompile);
Ambos enumeran una búsqueda de clave adecuada, pero solo los primeros enumeran una "Salida" de ObjectId. ¿Supongo que eso indica que el segundo es realmente un cortocircuito?
¿Alguien puede verificar si alguna vez se realizan sondas de una sola fila para ayudar con las estimaciones de fila? Parece incorrecto limitar la optimización solo a estimaciones de histograma cuando una búsqueda PK de una sola fila puede mejorar en gran medida la precisión de la búsqueda en el histograma (especialmente si hay potencial o historial de derrames). Cuando hay 10 de estas subuniones en una consulta real, idealmente estarían sucediendo en paralelo.
Una nota al margen, dado que sql_variant almacena su tipo base (SQL_VARIANT_PROPERTY = BaseType) dentro del campo en sí, esperaría que un convert () sea casi sin costo siempre que sea convertible "directamente" (por ejemplo, no cadena a decimal, sino int a int o tal vez int para bigint). Como eso no se conoce en el momento de la compilación, pero puede ser conocido por el usuario, tal vez una función "AssumeType (type, ...)" para sql_variants les permita ser tratados de manera más transparente.
declare @a bigint =
como lo ha hecho me parece una solución natural, ¿por qué es inaceptable?
CONVERT()
en columnas y luego unirlas. Esto ciertamente no es eficiente en la mayoría de los casos. En este caso en particular, solo se debe convertir un valor, por lo que probablemente no sea un problema, pero ¿qué índices tiene en la tabla? Los diseños de EAV generalmente funcionan bien, solo con una indexación adecuada (lo que significa una gran cantidad de índices en las tablas generalmente estrechas).