Preparar
Tengo problemas para entender una estimación de cardinalidad. Aquí está mi configuración de prueba:
- la versión 2010 de la base de datos Stack Overflow
- SQL Server 2017 CU15 + GDR (KB4505225) - 14.0.3192.2
- El nuevo CE (nivel de compatibilidad 140)
Tengo este proceso:
USE StackOverflow2010;
GO
CREATE OR ALTER PROCEDURE #sp_PostsByCommentCount
@CommentCount int
AS
BEGIN
SELECT *
FROM dbo.Posts p
WHERE
p.CommentCount = @CommentCount
OPTION (RECOMPILE);
END;
GO
No hay índices o estadísticas no agrupados en la dbo.Posts
tabla (hay un índice agrupado activado Id
).
Al solicitar un plan estimado para esto, las "filas estimadas" que salen dbo.Posts
son 1,934.99:
EXEC #sp_PostsByCommentCount @CommentCount = 51;
El siguiente objeto de estadísticas se creó automáticamente cuando solicité el plan estimado:
DBCC SHOW_STATISTICS('dbo.Posts', [_WA_Sys_00000006_0519C6AF]);
Los aspectos más destacados de eso son:
- Las estadísticas tienen una tasa de muestreo bastante baja de 1.81% (67,796 / 3,744,192)
- Solo se usaron 31 pasos de histograma
- El valor "Toda la densidad" es
0.03030303
(se muestrearon 33 valores distintos) - El último
RANGE_HI_KEY
en el histograma es 50, conEQ_ROWS
1
Pregunta
Pasar cualquier valor superior a 50 (hasta 2.147.483.647 inclusive) da como resultado la estimación de la fila de 1,934.99. ¿Qué cálculo o valor se utiliza para producir esta estimación? El estimador de cardinalidad heredado produce una estimación de 1 fila, por cierto.
Lo que he probado
Aquí hay algunas teorías que tenía, cosas que probé o fragmentos adicionales de información que pude desenterrar mientras investigaba esto.
Vector de densidad
Inicialmente pensé que sería el vector de densidad, igual que si lo hubiera usado OPTION (OPTIMIZE FOR UNKNOWN)
. Pero el vector de densidad para este objeto de estadísticas es 3,744,192 * 0.03030303 = 113,460, así que eso no es todo.
Eventos extendidos
Intenté ejecutar una sesión de evento extendido que recopilara el query_optimizer_estimate_cardinality
evento (que aprendí de la publicación de blog de Paul White, Estimación de la cardinalidad: combinación de estadísticas de densidad ), y obtuve este tipo de datos interesantes:
<CalculatorList>
<FilterCalculator CalculatorName="CSelCalcColumnInInterval" Selectivity="-1.000"
CalculatorFailed="true" TableName="[p]" ColumnName="CommentCount" />
<FilterCalculator CalculatorName="CSelCalcAscendingKeyFilter" Selectivity="0.001"
TableName="[p]" ColumnName="CommentCount" UseAverageFrequency="true"
StatId="4" />
</CalculatorList>
Entonces parece que CSelCalcAscendingKeyFilter
se utilizó la calculadora (la otra dice que falló, lo que sea que eso signifique). Esta columna no es una clave, ni única, ni necesariamente ascendente, sino lo que sea.
Hacer algunas búsquedas en Google de ese término me llevó a algunas publicaciones de blog:
- Joe Sack - La calculadora CSelCalcAscendingKeyFilter ,
- Itzik Ben-Gan - Busca y escanearás Parte II: Teclas ascendentes
Estas publicaciones indican que el nuevo CE basa estas estimaciones fuera del histograma en una combinación del vector de densidad y el contador de modificación de la estadística. Desafortunadamente, ya he descartado el vector de densidad (¡creo!), Y el contador de modificación es cero (de sys.dm_db_stats_properties
todos modos).
Banderas de seguimiento
Forrest sugirió que active TF 2363 para obtener más información sobre el proceso de estimación. Creo que lo más relevante de esa salida es esto:
Plan for computation:
CSelCalcAscendingKeyFilter(avg. freq., QCOL: [p].CommentCount)
Selectivity: 0.000516798
Este es un gran avance (¡gracias, Forrest!): Ese 0.000516798
número (que parece haberse redondeado inútilmente en el Selectivity="0.001"
atributo XE anterior) multiplicado por el número de filas en la tabla es la estimación que he estado buscando (1,934.99).
Probablemente me falta algo obvio, pero no he podido realizar ingeniería inversa sobre cómo se produce ese valor de selectividad dentro de la CSelCalcAscendingKeyFilter
calculadora.