Estimación de cardinalidad para> = y> para valor estadístico intra paso


9

Estoy tratando de entender cómo SQL Server intenta estimar las cláusulas where 'mayor que' y 'mayor que igual a' en SQL Server 2014.

Creo que entiendo la estimación de cardinalidad cuando da en el paso, por ejemplo, si lo hago

    select * from charge where charge_dt >= '1999-10-13 10:47:38.550'

La estimación de cardinalidad es 6672 que se puede calcular fácilmente como 32 (EQ_ROWS) + 6624 (RANGE_ROWS) + 16 (EQ_ROWS) = 6672 (histograma en la siguiente captura de pantalla)

ingrese la descripción de la imagen aquí

Pero cuando lo hago

    select * from charge where charge_dt >= '1999-10-13 10:48:38.550' 

(aumentó el tiempo a 10:48, así que no es un paso)

la estimación es 4844.13.

¿Cómo se calcula eso?

Respuestas:


9

La única dificultad es decidir cómo manejar los pasos del histograma cubiertos parcialmente por el intervalo de predicado de consulta. Los pasos completos del histograma cubiertos por el rango del predicado son triviales como se señala en la pregunta.

Estimador de cardinalidad heredada

F = fracción (entre 0 y 1) del rango de pasos cubierto por el predicado de consulta.

La idea básica es usar F(interpolación lineal) para determinar cuántos de los valores distintos dentro del paso están cubiertos por el predicado. Multiplicando este resultado por el número promedio de filas por valor distinto (suponiendo uniformidad), y sumando el paso filas iguales da la estimación de cardinalidad:

Cardinalidad = EQ_ROWS + (AVG_RANGE_ROWS * F * DISTINCT_RANGE_ROWS)

Se utiliza la misma fórmula para >y >=en el legado CE.

Nuevo estimador de cardinalidad

El nuevo CE modifica ligeramente el algoritmo anterior para diferenciar entre >y >=.

Tomando >primero, la fórmula es:

Cardinalidad = EQ_ROWS + (AVG_RANGE_ROWS * (F * (DISTINCT_RANGE_ROWS - 1)))

Pues >=es:

Cardinalidad = EQ_ROWS + (AVG_RANGE_ROWS * ((F * (DISTINCT_RANGE_ROWS - 1)) + 1))

Esto + 1refleja que cuando la comparación involucra igualdad, se supone una coincidencia (el supuesto de inclusión).

En el ejemplo de la pregunta, Fse puede calcular como:

DECLARE 
    @Q datetime = '1999-10-13T10:48:38.550',
    @K1 datetime = '1999-10-13T10:47:38.550',
    @K2 datetime = '1999-10-13T10:51:19.317';

DECLARE
    @QR float = DATEDIFF(MILLISECOND, @Q, @K2), -- predicate range
    @SR float = DATEDIFF(MILLISECOND, @K1, @K2) -- whole step range

SELECT
    F = @QR / @SR;

El resultado es 0.728219019233034 . Al conectar eso a la fórmula para >=con los otros valores conocidos:

Cardinalidad = EQ_ROWS + (AVG_RANGE_ROWS * ((F * (DISTINCT_RANGE_ROWS - 1)) + 1))
            = 16 + (16.1956 * ((0.728219019233034 * (409 - 1)) + 1))
            = 16 + (16.1956 * ((0.728219019233034 * 408) + 1))
            = 16 + (16.1956 * (297.113359847077872 + 1))
            = 16 + (16.1956 * 298.113359847077872)
            = 16 + 4828.1247307393343837632
            = 4844.1247307393343837632
            = 4844.12473073933 (para flotar precisión)

Este resultado está de acuerdo con la estimación de 4844.13 que se muestra en la pregunta.

La misma consulta que usa el CE heredado (por ejemplo, usando el indicador de traza 9481) debería producir una estimación de:

Cardinalidad = EQ_ROWS + (AVG_RANGE_ROWS * F * DISTINCT_RANGE_ROWS)
            = 16 + (16.1956 * 0.728219019233034 * 409)
            = 16 + 4823.72307468722
            = 4839.72307468722

Tenga en cuenta que la estimación sería la misma para el CE heredado >y para su >=uso.


4

La fórmula para estimar filas se vuelve un poco tonta cuando el filtro es "mayor que" o "menor que", pero es un número al que puede llegar.

Los números

Usando el paso 193, aquí están los números relevantes:

RANGE_ROWS = 6624

EQ_ROWS = 16

AVG_RANGE_ROWS = 16.1956

RANGE_HI_KEY del paso anterior = 1999-10-13 10: 47: 38.550

RANGE_HI_KEY del paso actual = 1999-10-13 10: 51: 19.317

Valor de la cláusula WHERE = 1999-10-13 10: 48: 38.550

La formula

1) Encuentra el ms entre las dos teclas hi de rango

SELECT DATEDIFF (ms, '1999-10-13 10:47:38.550', '1999-10-13 10:51:19.317')

El resultado es 220767 ms.

2) Ajusta el número de filas

Necesitamos encontrar las filas por milisegundo, pero antes de hacerlo, tenemos que restar AVG_RANGE_ROWS de RANGE_ROWS:

6624 - 16.1956 = 6607.8044 filas

3) Calcule las filas por ms con el número ajustado de filas:

6607.8044 filas / 220767 ms = .0299311 filas por ms

4) Calcule los ms entre el valor de la cláusula WHERE y el paso actual RANGE_HI_KEY

SELECT DATEDIFF (ms, '1999-10-13 10:48:38.550', '1999-10-13 10:51:19.317')

Esto nos da 160767 ms.

5) Calcule las filas en este paso en función de las filas por segundo:

.0299311 filas / ms * 160767 ms = 4811.9332 filas

6) ¿Recuerdas cómo restamos AVG_RANGE_ROWS anteriormente? Es hora de volver a agregarlos. Ahora que hemos terminado de calcular los números relacionados con las filas por segundo, también podemos agregar con seguridad el EQ_ROWS:

4811.9332 + 16.1956 + 16 = 4844.1288

Redondeado, esa es nuestra estimación de 4844.13.

Probar la fórmula

No pude encontrar ningún artículo o publicación de blog sobre por qué AVG_RANGE_ROWS se resta antes de que se calculen las filas por ms. Yo era capaz de confirmar que se tienen en cuenta en el cálculo, pero sólo en el último milisegundo - literalmente.

Usando la base de datos WideWorldImporters , realicé algunas pruebas incrementales y descubrí que la disminución en las estimaciones de filas es lineal hasta el final del paso, donde 1x AVG_RANGE_ROWS se explica de repente.

Aquí está mi consulta de muestra:

SELECT PickingCompletedWhen
FROM Sales.Orders
WHERE PickingCompletedWhen >= '2016-05-24 11:00:01.000000'

Actualicé las estadísticas para PickingCompletedWhen, luego obtuve el histograma:

DBCC SHOW_STATISTICS([sales.orders], '_WA_Sys_0000000E_44CA3770')

Histograma para _WA_Sys_0000000E_44CA3770 (últimos 3 pasos)

Para ver cómo disminuyen las filas estimadas a medida que nos acercamos a RANGE_HI_KEY, recolecté muestras durante todo el paso. La disminución es lineal, pero se comporta como si un número de filas igual al valor AVG_RANGE_ROWS simplemente no formara parte de la tendencia ... hasta que llegue a RANGE_HI_KEY y de repente caigan como una deuda cancelada cancelada. Puede verlo en los datos de muestra, especialmente en el gráfico.

ingrese la descripción de la imagen aquí

Tenga en cuenta la disminución constante en las filas hasta que lleguemos a RANGE_HI_KEY y luego a BOOM que el último fragmento AVG_RANGE_ROWS se sustrae repentinamente. También es fácil detectar en un gráfico.

ingrese la descripción de la imagen aquí

En resumen, el tratamiento extraño de AVG_RANGE_ROWS hace que el cálculo de las estimaciones de filas sea más complejo, pero siempre puede conciliar lo que está haciendo el CE.

¿Qué pasa con el retroceso exponencial?

El Retraso exponencial es el método que utiliza el nuevo (a partir de SQL Server 2014) el Estimador de cardinalidad para obtener mejores estimaciones cuando se utilizan múltiples estadísticas de una sola columna. Como esta pregunta era sobre una estadística de una sola columna, no involucra la fórmula EB.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.