He estado investigando los umbrales de muestreo con actualizaciones estadísticas en SQL Server (2012) y noté un comportamiento curioso. Básicamente, el número de filas muestreadas parece variar en algunas circunstancias, incluso con el mismo conjunto de datos.
Ejecuto esta consulta:
--Drop table if exists
IF (OBJECT_ID('dbo.Test')) IS NOT NULL DROP TABLE dbo.Test;
--Create Table for Testing
CREATE TABLE dbo.Test(Id INT IDENTITY(1,1) CONSTRAINT PK_Test PRIMARY KEY CLUSTERED, TextValue VARCHAR(20) NULL);
--Insert enough data so we have more than 8Mb (the threshold at which sampling kicks in)
INSERT INTO dbo.Test(TextValue)
SELECT TOP 1000000 'blahblahblah'
FROM sys.objects a, sys.objects b, sys.objects c, sys.objects d;
--Create Index on TextValue
CREATE INDEX IX_Test_TextValue ON dbo.Test(TextValue);
--Update Statistics without specifying how many rows to sample
UPDATE STATISTICS dbo.Test IX_Test_TextValue;
--View the Statistics
DBCC SHOW_STATISTICS('dbo.Test', IX_Test_TextValue) WITH STAT_HEADER;
Cuando miro el resultado de SHOW_STATISTICS, descubro que las "Filas muestreadas" varían con cada ejecución completa (es decir, la tabla se descarta, se recrea y se vuelve a llenar).
Por ejemplo:
Filas muestreadas
- 318618
- 319240
- 324198
- 314154
Mi expectativa era que esta cifra sería la misma cada vez que la tabla es idéntica. Por cierto, no obtengo este comportamiento si solo elimino los datos y los vuelvo a insertar.
No es una pregunta crítica, pero me interesaría entender qué está pasando.
sql-server
sql-server-2012
statistics
Matthew McGiffen
fuente
fuente
318618 = 1142*279
,319240 = 1144*279 + 64
,324198=1162*279
Y314154=1126
por lo que la varianza es el número de páginas de muestra.Respuestas:
Fondo
Los datos para el objeto de estadísticas se recopilan mediante una declaración del formulario:
Puede recopilar esta declaración con Extended Events o Profiler (
SP:StmtCompleted
).Las consultas de generación de estadísticas a menudo acceden a la tabla base (en lugar de a un índice no agrupado) para evitar la agrupación de valores que ocurre naturalmente en las páginas de índice no agrupadas.
El número de filas muestreadas depende del número de páginas enteras seleccionadas para el muestreo. Cada página de la tabla está seleccionada o no. Todas las filas en las páginas seleccionadas contribuyen a las estadísticas.
Números al azar
SQL Server usa un generador de números aleatorios para decidir si una página califica o no. El generador utilizado en este caso es el generador de números aleatorios de Lehmer con valores de parámetros como se muestra a continuación:
El valor de se calcula como la suma de:
Xseed
La parte entera baja de la
bigint
tabla base ( ),partition_id
p . Ej.El valor especificado en la
REPEATABLE
cláusula.UPDATE STATISTICS
, elREPEATABLE
valor es 1.m_randomSeed
elemento de la información de depuración interna del método de acceso que se muestra en los planes de ejecución cuando el indicador de seguimiento 8666 está habilitado, por ejemplo<Field FieldName="m_randomSeed" FieldValue="1" />
Para SQL Server 2012, este cálculo ocurre en
sqlmin!UnOrderPageScanner::StartScan
:donde memoria en
[rcx+30h]
contiene los 32 bits bajos de la identificación de partición y memoria en[rcx+2Ch]
contiene elREPEATABLE
valor en uso.El generador de números aleatorios se inicializa más tarde en el mismo método, llamando
sqlmin!RandomNumGenerator::Init
, donde la instrucción:... multiplica la semilla por
41A7
hexadecimal (16807 decimal = 7 5 ) como se muestra en la ecuación anterior.Los números aleatorios posteriores (para páginas individuales) se generan utilizando el mismo código básico incluido
sqlmin!UnOrderPageScanner::SetupSubScanner
.StatMan
Para la
StatMan
consulta de ejemplo que se muestra arriba, se recopilarán las mismas páginas que para la instrucción T-SQL:Esto coincidirá con la salida de:
Caso extremo
Una consecuencia del uso del generador de números aleatorios MINSTD Lehmer es que los valores semilla cero e int.max no deben usarse, ya que esto dará como resultado que el algoritmo produzca una secuencia de ceros (seleccionando cada página).
El código detecta cero y utiliza un valor del 'reloj' del sistema como semilla en ese caso. No hace lo mismo si la semilla es int.max (
0x7FFFFFFF
= 2 31 - 1).Podemos diseñar este escenario ya que la semilla inicial se calcula como la suma de los 32 bits bajos de la identificación de la partición y el
REPEATABLE
valor. ElREPEATABLE
valor que dará como resultado que la semilla sea int.max y, por lo tanto, cada página que se seleccione para la muestra es:Trabajando eso en un ejemplo completo:
Eso seleccionará cada fila en cada página, independientemente de lo
TABLESAMPLE
que diga la cláusula (incluso cero por ciento).fuente
Esta es una excelente pregunta! Comenzaré con lo que sé con certeza y luego pasaré a la especulación. Muchos detalles sobre esto en mi blog aquí .
Las actualizaciones de estadísticas muestreadas se usan
TABLESAMPLE
detrás de escena. Es bastante fácil encontrar documentación sobre eso en línea. Sin embargo, creo que no se sabe bien que las filas devueltasTABLESAMPLE
dependen parcialmentehobt_id
del objeto. Cuando suelta yhobt_id
vuelve a crear el objeto, obtiene un nuevo, por lo que las filas devueltas por muestreo aleatorio son diferentes.Si elimina y vuelve a insertar los datos,
hobt_id
permanece igual. Mientras los datos se presenten de la misma manera en el disco (una exploración de orden de asignación devuelve los mismos resultados en el mismo orden), los datos muestreados no deberían cambiar.También puede cambiar el número de filas muestreadas reconstruyendo el índice agrupado en la tabla. Por ejemplo:
En cuanto a por qué sucede eso, creo que es porque SQL Server escanea el índice agrupado en lugar del índice no agrupado cuando recopila estadísticas muestreadas en un índice. También creo que hay un valor oculto (para aquellos de nosotros que rastreamos las consultas ocultas de actualización de estadísticas) para
REPEATABLE
usar conTABLESAMPLE
. No he probado nada de eso, pero explica por qué su histograma y las filas muestreadas cambian con una reconstrucción del índice agrupado.fuente
Vi esto en Inside Microsoft SQL Server 2008: Consulta T-SQL por Itzik Ben-Gan y no puedo agregarlo como comentario, así que lo publico aquí, creo que también es interesante para otros:
Ver también Muestreo usando TABLESAMPLE por Roji. P. Thomas.
fuente