¿Cómo se decide el número de pasos del histograma en Estadísticas en SQL Server?
¿Por qué está restringido a 200 pasos a pesar de que mi columna clave tiene más de 200 valores distintos? ¿Hay algún factor decisivo?
Manifestación
Definición de esquema
CREATE TABLE histogram_step
(
id INT IDENTITY(1, 1),
name VARCHAR(50),
CONSTRAINT pk_histogram_step PRIMARY KEY (id)
)
Insertar 100 registros en mi tabla
INSERT INTO histogram_step
(name)
SELECT TOP 100 name
FROM sys.syscolumns
Actualizar y verificar las estadísticas
UPDATE STATISTICS histogram_step WITH fullscan
DBCC show_statistics('histogram_step', pk_histogram_step)
Pasos del histograma:
+--------------+------------+---------+---------------------+----------------+
| RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | AVG_RANGE_ROWS |
+--------------+------------+---------+---------------------+----------------+
| 1 | 0 | 1 | 0 | 1 |
| 3 | 1 | 1 | 1 | 1 |
| 5 | 1 | 1 | 1 | 1 |
| 7 | 1 | 1 | 1 | 1 |
| 9 | 1 | 1 | 1 | 1 |
| 11 | 1 | 1 | 1 | 1 |
| 13 | 1 | 1 | 1 | 1 |
| 15 | 1 | 1 | 1 | 1 |
| 17 | 1 | 1 | 1 | 1 |
| 19 | 1 | 1 | 1 | 1 |
| 21 | 1 | 1 | 1 | 1 |
| 23 | 1 | 1 | 1 | 1 |
| 25 | 1 | 1 | 1 | 1 |
| 27 | 1 | 1 | 1 | 1 |
| 29 | 1 | 1 | 1 | 1 |
| 31 | 1 | 1 | 1 | 1 |
| 33 | 1 | 1 | 1 | 1 |
| 35 | 1 | 1 | 1 | 1 |
| 37 | 1 | 1 | 1 | 1 |
| 39 | 1 | 1 | 1 | 1 |
| 41 | 1 | 1 | 1 | 1 |
| 43 | 1 | 1 | 1 | 1 |
| 45 | 1 | 1 | 1 | 1 |
| 47 | 1 | 1 | 1 | 1 |
| 49 | 1 | 1 | 1 | 1 |
| 51 | 1 | 1 | 1 | 1 |
| 53 | 1 | 1 | 1 | 1 |
| 55 | 1 | 1 | 1 | 1 |
| 57 | 1 | 1 | 1 | 1 |
| 59 | 1 | 1 | 1 | 1 |
| 61 | 1 | 1 | 1 | 1 |
| 63 | 1 | 1 | 1 | 1 |
| 65 | 1 | 1 | 1 | 1 |
| 67 | 1 | 1 | 1 | 1 |
| 69 | 1 | 1 | 1 | 1 |
| 71 | 1 | 1 | 1 | 1 |
| 73 | 1 | 1 | 1 | 1 |
| 75 | 1 | 1 | 1 | 1 |
| 77 | 1 | 1 | 1 | 1 |
| 79 | 1 | 1 | 1 | 1 |
| 81 | 1 | 1 | 1 | 1 |
| 83 | 1 | 1 | 1 | 1 |
| 85 | 1 | 1 | 1 | 1 |
| 87 | 1 | 1 | 1 | 1 |
| 89 | 1 | 1 | 1 | 1 |
| 91 | 1 | 1 | 1 | 1 |
| 93 | 1 | 1 | 1 | 1 |
| 95 | 1 | 1 | 1 | 1 |
| 97 | 1 | 1 | 1 | 1 |
| 99 | 1 | 1 | 1 | 1 |
| 100 | 0 | 1 | 0 | 1 |
+--------------+------------+---------+---------------------+----------------+
Como podemos ver, hay 53 pasos en el histograma.
Nuevamente insertando unos pocos miles de registros
INSERT INTO histogram_step
(name)
SELECT TOP 10000 b.name
FROM sys.syscolumns a
CROSS JOIN sys.syscolumns b
Actualizar y verificar las estadísticas
UPDATE STATISTICS histogram_step WITH fullscan
DBCC show_statistics('histogram_step', pk_histogram_step)
Ahora los pasos del histograma se reducen a 4 pasos.
+--------------+------------+---------+---------------------+----------------+
| RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | AVG_RANGE_ROWS |
+--------------+------------+---------+---------------------+----------------+
| 1 | 0 | 1 | 0 | 1 |
| 10088 | 10086 | 1 | 10086 | 1 |
| 10099 | 10 | 1 | 10 | 1 |
| 10100 | 0 | 1 | 0 | 1 |
+--------------+------------+---------+---------------------+----------------+
Nuevamente insertando unos pocos miles de registros
INSERT INTO histogram_step
(name)
SELECT TOP 100000 b.name
FROM sys.syscolumns a
CROSS JOIN sys.syscolumns b
Actualizar y verificar las estadísticas
UPDATE STATISTICS histogram_step WITH fullscan
DBCC show_statistics('histogram_step', pk_histogram_step)
Ahora los pasos del histograma se reducen a 3 pasos.
+--------------+------------+---------+---------------------+----------------+
| RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | AVG_RANGE_ROWS |
+--------------+------------+---------+---------------------+----------------+
| 1 | 0 | 1 | 0 | 1 |
| 110099 | 110097 | 1 | 110097 | 1 |
| 110100 | 0 | 1 | 0 | 1 |
+--------------+------------+---------+---------------------+----------------+
¿Alguien puede decirme cómo se deciden estos pasos?
sql-server
statistics
P ரதீப்
fuente
fuente
Respuestas:
Limitaré esta publicación para discutir estadísticas de una sola columna porque ya será bastante larga y le interesa cómo SQL Server agrupa los datos en pasos de histograma. Para las estadísticas de varias columnas, el histograma solo se crea en la columna inicial.
Cuando SQL Server determina que se necesita una actualización de estadísticas, inicia una consulta oculta que lee todos los datos de una tabla o una muestra de los datos de la tabla. Puede ver estas consultas con eventos extendidos. Hay una función llamada
StatMan
dentro de SQL Server que participa en la creación de los histogramas. Para los objetos de estadísticas simples, hay al menos dos tipos diferentes deStatMan
consultas (hay consultas diferentes para actualizaciones rápidas de estadísticas y sospecho que la función de estadísticas incrementales en tablas particionadas también usa una consulta diferente).El primero solo toma todos los datos de la tabla sin ningún filtro. Puede ver esto cuando la tabla es muy pequeña o si reúne estadísticas con la
FULLSCAN
opción:SQL Server elige el tamaño de muestra automático en función del tamaño de la tabla (creo que es tanto el número de filas como las páginas de la tabla). Si una tabla es demasiado grande, el tamaño de la muestra automática cae por debajo del 100%. Esto es lo que obtuve para la misma tabla con 1M de filas:
TABLESAMPLE
está documentado pero StatMan y step_direction no lo están. aquí SQL Server muestrea alrededor del 66,6% de los datos de la tabla para crear el histograma. Lo que esto significa es que podría obtener un número diferente de pasos de histograma al actualizar estadísticas (sinFULLSCAN
) en los mismos datos. Nunca he observado esto en la práctica, pero no veo por qué no sería posible.Ejecutemos algunas pruebas en datos simples para ver cómo cambian las estadísticas con el tiempo. A continuación hay un código de prueba que escribí para insertar enteros secuenciales en una tabla, recopilar estadísticas después de cada inserción y guardar información sobre las estadísticas en una tabla de resultados. Comencemos simplemente insertando 1 fila a la vez hasta 10000. Banco de pruebas:
Para estos datos, el número de pasos del histograma aumenta rápidamente a 200 (primero alcanza el número máximo de pasos con 397 filas), permanece en 199 o 200 hasta que 1485 filas estén en la tabla, luego disminuye lentamente hasta que el histograma solo tiene 3 o 4 pasos. Aquí hay un gráfico de todos los datos:
Aquí está el histograma para 10k filas:
¿Es un problema que el histograma solo tenga 3 pasos? Parece que la información se conserva desde nuestro punto de vista. Tenga en cuenta que debido a que el tipo de datos es un INTEGER, podemos calcular cuántas filas hay en la tabla para cada número entero de 1 a 10000. Por lo general, SQL Server también puede resolver esto, aunque hay algunos casos en los que esto no funciona del todo . Ver esta publicación SE para un ejemplo de esto.
¿Qué crees que sucederá si eliminamos una sola fila de la tabla y actualizamos las estadísticas? Idealmente, obtendríamos otro paso de histograma para mostrar que el entero que falta ya no está en la tabla.
Eso es un poco decepcionante. Si estuviéramos construyendo un histograma a mano, agregaríamos un paso para cada valor faltante. SQL Server está utilizando un algoritmo de propósito general, por lo que para algunos conjuntos de datos podemos encontrar un histograma más adecuado que el código que utiliza. Por supuesto, la diferencia práctica entre obtener 0 o 1 fila de una tabla es muy pequeña. Obtengo los mismos resultados al probar con 20000 filas, cada número entero tiene 2 filas en la tabla. El histograma no gana pasos cuando borro datos.
Si pruebo con 1 millón de filas con cada número entero que tiene 100 filas en la tabla, obtengo resultados ligeramente mejores, pero aún puedo construir un mejor histograma a mano.
Histograma final:
Probemos más con enteros secuenciales pero con más filas en la tabla. Tenga en cuenta que para las tablas que son demasiado pequeñas, especificar manualmente un tamaño de muestra no tendrá ningún efecto, por lo que agregaré 100 filas en cada inserción y reuniré estadísticas cada vez hasta 1 millón de filas. Veo un patrón similar al anterior, excepto que una vez que llego a 637300 filas en la tabla, ya no pruebo el 100% de las filas en la tabla con la frecuencia de muestreo predeterminada. A medida que gano filas, aumenta el número de pasos del histograma. Quizás esto se deba a que SQL Server termina con más huecos en los datos a medida que aumenta el número de filas sin muestrear en la tabla. No llego a 200 pasos incluso en filas de 1 M, pero si seguía agregando filas, espero llegar allí y eventualmente comenzar a volver a bajar.
El eje X es el número de filas en la tabla. A medida que aumenta el número de filas, las filas muestreadas varían un poco y no superan los 650k.
Ahora hagamos algunas pruebas simples con datos VARCHAR.
Aquí estoy insertando 200 números (como cadenas) junto con NULL.
Tenga en cuenta que NULL siempre obtiene su propio paso de histograma cuando se encuentra en la tabla. SQL Server podría haberme dado exactamente 201 pasos para preservar toda la información, pero no lo hizo. Técnicamente, la información se pierde porque '1111' clasifica entre '1' y '2', por ejemplo.
Ahora intentemos insertar diferentes caracteres en lugar de solo enteros:
No hay diferencia real con respecto a la última prueba.
Ahora intentemos insertar caracteres pero poniendo diferentes números de cada carácter en la tabla. Por ejemplo,
CHAR(11)
tiene 1 fila,CHAR(12)
tiene 2 filas, etc.Como antes, todavía no obtengo exactamente 200 pasos de histograma. Sin embargo, muchos de los pasos tienen
RANGE_ROWS
de 0.Para la prueba final, voy a insertar una cadena aleatoria de 5 caracteres en cada ciclo y reunir estadísticas cada vez. Aquí está el código de la cadena aleatoria:
Aquí está el gráfico de filas en la tabla frente a los pasos del histograma:
Tenga en cuenta que el número de pasos no desciende por debajo de 100 una vez que comienza a subir y bajar. Escuché en alguna parte (pero no puedo obtenerlo ahora) que el algoritmo de creación de histograma de SQL Server combina los pasos del histograma ya que se les acaba el espacio. Por lo tanto, puede terminar con cambios drásticos en la cantidad de pasos simplemente agregando un poco de información. Aquí hay una muestra de los datos que encontré interesantes:
Incluso cuando se muestrea con
FULLSCAN
, agregar una sola fila puede aumentar el número de pasos en 10, mantenerlo constante, luego disminuirlo en 2, luego disminuirlo en 3.¿Qué podemos resumir de todo esto? No puedo probar nada de esto, pero estas observaciones parecen ser ciertas:
RANGE_ROWS
= 0.RANGE_HI_KEY
en la tabla.DISTINCT_RANGE_ROWS
oRANGE_ROWS
. Por ejemplo, 255 aparece un montón de veces paraRANGE_ROWS
yDISTINCT_RANGE_ROWS
para el caso de prueba final aquí.¿Cuándo es todo esto un problema? Es un problema cuando una consulta funciona mal debido a un histograma que no puede representar la distribución de datos de manera que el optimizador de consultas tome buenas decisiones. Creo que hay una tendencia a pensar que tener más pasos de histograma siempre es mejor y que haya consternación cuando SQL Server genera un histograma en millones de filas o más, pero no usa exactamente 200 o 201 pasos de histograma. Sin embargo, he visto muchos problemas de estadísticas incluso cuando el histograma tiene 200 o 201 pasos. No tenemos ningún control sobre cuántos pasos de histograma genera SQL Server para un objeto de estadísticas, por lo que no me preocuparía. Sin embargo, hay algunos pasos que puede seguir cuando experimenta consultas de bajo rendimiento causadas por problemas de estadísticas. Daré una descripción extremadamente breve.
Recopilar estadísticas completas puede ayudar en algunos casos. Para tablas muy grandes, el tamaño de la muestra automática puede ser inferior al 1% de las filas de la tabla. Algunas veces eso puede llevar a malos planes dependiendo de la interrupción de datos en la columna. La documentación de Microsofts para CREAR ESTADÍSTICAS y ACTUALIZAR ESTADÍSTICAS dice lo mismo:
En algunos casos, la creación de estadísticas filtradas puede ayudar. Puede tener una columna con datos asimétricos y muchos valores distintos diferentes. Si hay ciertos valores en los datos que comúnmente se filtran, puede crear un histograma de estadísticas solo para esos valores comunes. El optimizador de consultas puede usar las estadísticas definidas en un rango de datos más pequeño en lugar de las estadísticas definidas en todos los valores de columna. Aún no tiene garantizado obtener 200 pasos en el histograma, pero si crea las estadísticas filtradas en un solo valor, un paso de histograma lo hará.
Usar una vista particionada es una forma de obtener efectivamente más de 200 pasos para una tabla. Suponga que puede dividir fácilmente una tabla grande en una tabla por año. Crea una
UNION ALL
vista que combina todas las tablas anuales. Cada tabla tendrá su propio histograma. Tenga en cuenta que las nuevas estadísticas incrementales introducidas en SQL Server 2014 solo permiten que las actualizaciones de estadísticas sean más eficientes. El optimizador de consultas no usará las estadísticas que se crean por partición.Hay muchas más pruebas que podrían ejecutarse aquí, así que te animo a que experimentes. Hice esta prueba en SQL Server 2014 express, así que realmente no hay nada que te detenga.
fuente