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

Número estimado de filas para leer

No me malinterpreten:me encanta la propiedad Lectura de filas reales que vimos llegar a los planes de ejecución de SQL Server a fines de 2015. Pero en SQL Server 2016 SP1, hace menos de dos meses (y teniendo en cuenta que tuvimos Navidad en el medio, no creo que cuente mucho tiempo desde entonces), obtuvimos otra adición emocionante: Número estimado de filas para leer (Oh, y esto se debe en cierta medida al elemento de conexión que envié, demostrando que vale la pena enviar elementos de conexión y haciendo que esta publicación sea elegible para el martes de T-SQL de este mes, organizado por Brent Ozar (@brento) sobre el tema de los elementos de conexión ).

Recapitulemos un momento... cuando SQL Engine accede a los datos de una tabla, utiliza una operación de exploración o una operación de búsqueda. Y a menos que Seek tenga un Seek Predicate que pueda acceder como máximo a una fila (porque está buscando una coincidencia de igualdad en un conjunto de columnas, podría ser solo una columna, que se sabe que es única), entonces Seek realizará una RangeScan, y se comporta como un Scan, solo en el subconjunto de filas que satisface el Seek Predicate.

Las filas satisfechas por un predicado de búsqueda (en el caso de RangeScan de una operación de búsqueda) o todas las filas de la tabla (en el caso de una operación de exploración) se tratan esencialmente de la misma manera. Ambos pueden finalizar antes de tiempo si no se solicitan más filas del operador a su izquierda, por ejemplo, si un operador superior en algún lugar ya tomó suficientes filas, o si un operador de combinación no tiene más filas con las que comparar. Y ambos pueden ser filtrados aún más por un Predicado Residual (que se muestra como la propiedad 'Predicado') antes de que el operador Scan/Seek sirva las filas. Las propiedades "Número de filas" y "Número estimado de filas" nos dirían cuántas filas se esperaba que produjera el operador, pero no teníamos ninguna información sobre cuántas filas se filtrarían solo con el Predicado de búsqueda. Pudimos ver TableCardinality, pero esto solo fue realmente útil para los operadores de Scan, donde existía la posibilidad de que Scan pudiera buscar en toda la tabla las filas que necesitaba. No fue útil en absoluto para búsquedas.

La consulta que estoy ejecutando aquí es contra la base de datos de WideWorldImporters y es:

SELECT COUNT(*)
FROM Sales.Orders
WHERE SalespersonPersonID = 7
AND YEAR(OrderDate) = 2013
AND MONTH(OrderDate) = 4;

Además, tengo un índice en juego:

CREATE NONCLUSTERED INDEX rf_Orders_SalesPeople_OrderDate 
  ON Sales.Orders (SalespersonPersonID, OrderDate);

Este índice cubre (la consulta no necesita ninguna otra columna para obtener su respuesta) y se ha diseñado para que se pueda usar un predicado de búsqueda en SalespersonPersonID, filtrando rápidamente los datos a un rango más pequeño. Las funciones en OrderDate significan que esos dos últimos predicados no se pueden usar dentro del Seek Predicate, por lo que se relegan al Predicado Residual en su lugar. Una mejor consulta filtraría esas fechas usando OrderDate>='20130401' AND OrderDate <'20130501', pero estoy imaginando un escenario aquí que es demasiado común...

Ahora, si ejecuto la consulta, puedo ver el impacto de los predicados residuales. Plan Explorer incluso da esa útil advertencia sobre la que había escrito antes.

Puedo ver muy claramente que RangeScan tiene 7276 filas y que Residual Predicate filtra esto hasta 149. Plan Explorer muestra más información sobre esto en la información sobre herramientas:

Pero sin ejecutar la consulta, no puedo ver esa información. Simplemente no está allí. Las propiedades en el plan estimado no lo tienen:

Y estoy seguro de que no necesito recordártelo:esta información tampoco está presente en el caché del plan. Habiendo tomado el plan del caché usando:

SELECT p.query_plan, t.text
FROM sys.dm_exec_cached_plans c
CROSS APPLY sys.dm_exec_query_plan(c.plan_handle) p
CROSS APPLY sys.dm_exec_sql_text(c.plan_handle) t
WHERE t.text LIKE '%YEAR%';

Lo abrí y, efectivamente, no hay señales de ese valor de 7.276. Se ve igual que el plan estimado que acabo de mostrar.

Sacar los planes del caché es donde los valores estimados cobran importancia. No es solo que prefiera no ejecutar consultas potencialmente costosas en las bases de datos de los clientes. Consultar el caché del plan es una cosa, pero ejecutar consultas para obtener los datos reales es mucho más difícil.

Con SQL 2016 SP1 instalado, gracias a ese elemento Connect, ahora puedo ver la propiedad Número estimado de filas para leer en los planes estimados y en la memoria caché del plan. La información sobre herramientas del operador que se muestra aquí se tomó de la memoria caché, y puedo ver fácilmente que la propiedad Estimado muestra 7276, así como la advertencia residual:

Esto es algo que podría hacer en un cuadro de cliente, buscando en el caché situaciones en planes problemáticos donde la proporción de Número estimado de filas para leer y Número estimado de filas no es excelente. Potencialmente, alguien podría hacer un proceso que verificara todos los planes en el caché, pero no es algo que yo haya hecho.

Una lectura astuta habrá notado que las filas reales que surgieron de este operador fueron 149, mucho más pequeñas que las 1382.56 estimadas. Pero cuando busco predicados residuales que tienen que verificar demasiadas filas, la proporción de 1382,56 :7276 sigue siendo significativa.

Ahora que descubrimos que esta consulta es ineficaz sin necesidad de ejecutarla, la forma de solucionarlo es asegurarse de que el predicado residual sea lo suficientemente SARGable. Esta consulta…

SELECT COUNT(*) 
FROM Sales.Orders
WHERE SalespersonPersonID = 7 
AND OrderDate >= '20130401' 
AND OrderDate <  '20130501';

…da los mismos resultados y no tiene Predicado Residual. En esta situación, el valor del Número estimado de filas para leer es idéntico al Número estimado de filas y la ineficiencia desaparece:

Como se mencionó anteriormente, esta publicación es parte del martes de T-SQL de este mes. ¿Por qué no se dirige allí para ver qué otras solicitudes de funciones se han otorgado recientemente?