SqlServer, plan de consulta y optimización (Tuning) (2)
Datos correlacionados
En la entrada anterior hablamos sobre cuando puede fallar el optimizador, que podría hacer fallar el path suboptimo pensado por el motor.
Se me ha hecho muy fácil engañar algunos motores y hacerles meter la pata, con sql server se complica un poco mas y las situaciones por donde podemos hacer "pinchar" al optimizador son pocas. Una de ellas es tener datos correlacionados.
Para el ejemplo de la entrega vamos a manejarnos con una tabla de vehiculos con campos marca, modelo y motor, la tabla seria la siguiente:
Tabla
CREATE TABLE [dbo].[Vehiculo](
[IdVehiculo] [int] IDENTITY(1,1) NOT NULL,
[Dominio] [char](20) NOT NULL,
[Observacion] [text] NOT NULL,
[Marca] [char](20) NOT NULL,
[Modelo] [char](20) NOT NULL,
[Motor] [char](20) NOT NULL,
CONSTRAINT [PK_Vehiculo] PRIMARY KEY CLUSTERED
(
[IdVehiculo] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
En la misma insertamos aproximadamente 100000 VW GOL POWER con motor VW 1.6, insertamos también alrededor de 50000 de otros vehículos, de otras marcas y modelos
¿Porque es difícil que se equivoque el sql server?
El sql server maneja estadísticas para tablas con mas de 500 registros con una buena precisión, el sql server sabe en muchos casos, y por ejemplo para nuestra tabla de vehículo cuantos FIAT, cuando VW o cuantos FORD hay, sabe también cuantos GOL POWER hay y cuantos PALIO (Las estadisticas las fue generando a medida que se ejecutaron selects con condiciones de selección aplicadas a los campos).
Si pidiéramos al sqlserver que nos retorne todos los vehículos PALIO el mismo sabría con buena precisión cuantos hay, escogería una estrategia de búsqueda adecuada.
Lo que no sabe y no puede saber es la correlación que existe entre, por ejemplo, el modelo GOL POWER y la marca VW, hay una relación estricta entre marca y modelo y sí alguien podría decir,
-El problema es que la base esta mal diseñada, deberías tener tabla de modelos y tabla de marcas, ambas relacionadas
Si es cierto para este caso, la realidad es que las bases con las que nos toca trabajar no siempre están bien diseñadas y ademas hay casos donde la relación es muy estrecha pero no definitiva.
Por ejemplo si preguntáramos Franceses que hablan Francés obtendríamos a casi todos los Franceses, pero no necesariamente a todos.
En cualquier caso si pidiéramos al SqlServer que nos retorne todos los VW que son GOL POWER es probable que lo pongamos en un aprieto a la hora de estimar la cantidad de registros que retornaría la consulta, una mala estimación de este tipo desencadena una serie de malas decisiones a la hora de elegir la estrategia de join, la estrategia de búsqueda etc.
En las ultimas versiones de sql server (2008 o superior) existe la posibilidad de explicarle al motor la situación mediante indices especiales, es una opción valida pero algo oscura.
Me da la sensación que esos indices tan específicos pueden generar problemas entre implementaciones o durante el ciclo de vida de la base de datos si no se tiene control de su existencia y de su carácter especifico.
Miren todos como se equivoca el sql server
En la siguiente imagen se puede ver la pésima estimación que hace el sqlserver .
Si examinamos el plan de consulta el mismo espera recibir algo así como 1125 filas, veamos que fue lo que efectivamente recibimos luego de ejecutar la consulta...
La consulta devolvió 100001 registros, la diferencia es importante en una tabla con 150000 registros, y como se menciono antes ya no se puede esperar mucho del plan de consulta después de semejante error.
En la próxima entrada vamos a ver como este error degenera en la perdida de rendimiento de la consulta.