¿Un nuevo índice actualiza las estadísticas?


43

He estado haciendo el curso MS10775A la semana pasada y surgió una pregunta que el entrenador no pudo responder de manera confiable es:

¿Un reindexar actualiza las estadísticas?

Encontramos discusiones en línea argumentando que sí y que no.


Es útil tener en cuenta que REINDEXsí actualiza las estadísticas de columna como un efecto secundario de la reconstrucción del índice; no es necesario actualizar las estadísticas. Los datos en la tabla no cambian. Son los mismos datos, solo a) movió su ubicación en la bandeja giratoria (cuando se reorganiza una página), o b) se sentó en una página diferente (en el caso de una reconstrucción). Por lo tanto: una re-índice hace (algunos) las estadísticas de actualización: no hay necesidad de hacerlo.
Ian Boyd

Respuestas:


51

Puede tener en cuenta lo siguiente al preocuparse por actualizar las estadísticas (copiado de Reconstruir índices frente a Actualizar estadísticas (Benjamin Nevarez)

  1. Por defecto, la UPDATE STATISTICSdeclaración usa solo una muestra de registros de la tabla. El uso UPDATE STATISTICS WITH FULLSCANescaneará toda la tabla.

  2. Por defecto, la UPDATE STATISTICSdeclaración actualiza las estadísticas de índice y columna. El uso de la COLUMNSopción actualizará solo las estadísticas de columna. El uso de la INDEXopción actualizará solo las estadísticas de índice.

  3. La reconstrucción de un índice , por ejemplo, mediante el uso ALTER INDEX … REBUILDtambién actualizará las estadísticas del índice con el equivalente de usar a WITH FULLSCAN menos que la tabla esté particionada, en cuyo caso las estadísticas solo se muestrean (se aplica a SQL Server 2012 y versiones posteriores).

  4. Las estadísticas que se crearon manualmente usando CREATE STATISTICSno se actualizan por ninguna ALTER INDEX ... REBUILDoperación, incluida ALTER TABLE ... REBUILD. ALTER TABLE ... REBUILDactualiza las estadísticas para el índice agrupado, si se define uno en la tabla que se está reconstruyendo.

  5. La reorganización de un índice , por ejemplo, el uso ALTER INDEX … REORGANIZEno actualiza ninguna estadística.

La respuesta breve es que debe usar UPDATE STATISTICSpara actualizar las estadísticas de columna y que una reconstrucción de índice actualizará solo las estadísticas de índice. Puede forzar una actualización de todas las estadísticas en una tabla, incluidas las estadísticas de índice y las estadísticas creadas manualmente, con la UPDATE STATISTICS (tablename) WITH FULLSCAN;sintaxis.

El siguiente código ilustra las reglas encapsuladas anteriormente:

Primero, crearemos una tabla con un par de columnas y un índice agrupado:

USE tempdb;

IF OBJECT_ID(N'dbo.SomeTable', N'U') IS NOT NULL
DROP TABLE dbo.SomeTable;

CREATE TABLE dbo.SomeTable
(
    rn int NOT NULL IDENTITY(1,1)
        CONSTRAINT pk
        PRIMARY KEY NONCLUSTERED
    , i int NOT NULL INDEX i 
    , d sysname NOT NULL
) ON [PRIMARY] WITH (DATA_COMPRESSION = NONE);

CREATE UNIQUE CLUSTERED INDEX cx ON dbo.SomeTable (i, d);

CREATE STATISTICS d ON dbo.SomeTable (d) WITH FULLSCAN;

INSERT INTO dbo.SomeTable (d, i)
SELECT c1.name, c1.id
FROM sys.syscolumns c1;

Esta consulta muestra la fecha en que cada objeto de estadísticas se actualizó por última vez:

SELECT ObjectName = sc.name + N'.' + o.name
    , StatsName = s.name
    , StatsDate = STATS_DATE(s.object_id, s.stats_id)
FROM sys.stats s
    INNER JOIN sys.objects o ON s.object_id = o.object_id
    INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE sc.name = N'dbo'
    AND o.name = N'SomeTable';

Los resultados muestran que aún no se han realizado actualizaciones, lo cual es correcto desde que acabamos de crear la tabla:

╔═══════════════╦═══════════╦═══════════╗
║ ObjectName ║ StatsName ║ StatsDate ║
╠═══════════════╬═══════════╬═══════════╣
║ dbo.SomeTable ║ cx ║ NULL ║
Bo dbo.SomeTable ║ i ║ NULL ║
║ dbo.SomeTable ║ pk ║ NULL ║
║ dbo.SomeTable ║ d ║ NULL ║
╚═══════════════╩═══════════╩═══════════╝

Vamos a reconstruir toda la tabla y ver si eso actualiza las estadísticas:

ALTER TABLE dbo.SomeTable REBUILD;

SELECT ObjectName = sc.name + N'.' + o.name
    , StatsName = s.name
    , StatsDate = STATS_DATE(s.object_id, s.stats_id)
FROM sys.stats s
    INNER JOIN sys.objects o ON s.object_id = o.object_id
    INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE sc.name = N'dbo'
    AND o.name = N'SomeTable';
╔═══════════════╦═══════════╦═════════════════════ ════╗
║ ObjectName ║ StatsName ║ StatsDate ║
╠═══════════════╬═══════════╬═════════════════════ ════╣
║ dbo.SomeTable ║ cx ║ 2018-09-17 14: 09: 13.590 ║
Bo dbo.SomeTable ║ i ║ NULL ║
║ dbo.SomeTable ║ pk ║ NULL ║
║ dbo.SomeTable ║ d ║ NULL ║
╚═══════════════╩═══════════╩═════════════════════ ════╝

Los resultados muestran que solo se actualizaron las estadísticas del índice agrupado .

A continuación, realizamos una UPDATE STATSoperación discreta :

UPDATE STATISTICS dbo.SomeTable(d) WITH FULLSCAN;

SELECT ObjectName = sc.name + N'.' + o.name
    , StatsName = s.name
    , StatsDate = STATS_DATE(s.object_id, s.stats_id)
FROM sys.stats s
    INNER JOIN sys.objects o ON s.object_id = o.object_id
    INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE sc.name = N'dbo'
    AND o.name = N'SomeTable';

Como puede ver, acabamos de actualizar las estadísticas en la dcolumna:

╔═══════════════╦═══════════╦═════════════════════ ════╗
║ ObjectName ║ StatsName ║ StatsDate ║
╠═══════════════╬═══════════╬═════════════════════ ════╣
║ dbo.SomeTable ║ cx ║ 2018-09-17 14: 09: 13.590 ║
Bo dbo.SomeTable ║ i ║ NULL ║
║ dbo.SomeTable ║ pk ║ NULL ║
║ dbo.SomeTable ║ d ║ 2018-09-17 14: 09: 13.597 ║
╚═══════════════╩═══════════╩═════════════════════ ════╝

Ahora, actualizaremos las estadísticas de toda la tabla:

UPDATE STATISTICS dbo.SomeTable WITH FULLSCAN;

SELECT ObjectName = sc.name + N'.' + o.name
    , StatsName = s.name
    , StatsDate = STATS_DATE(s.object_id, s.stats_id)
FROM sys.stats s
    INNER JOIN sys.objects o ON s.object_id = o.object_id
    INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE sc.name = N'dbo'
    AND o.name = N'SomeTable';
╔═══════════════╦═══════════╦═════════════════════ ════╗
║ ObjectName ║ StatsName ║ StatsDate ║
╠═══════════════╬═══════════╬═════════════════════ ════╣
║ dbo.SomeTable ║ cx ║ 2018-09-17 14: 09: 13.600 ║
Bo dbo.SomeTable ║ i ║ 2018-09-17 14: 09: 13.600 ║
║ dbo.SomeTable ║ pk ║ 2018-09-17 14: 09: 13.603 ║
║ dbo.SomeTable ║ d ║ 2018-09-17 14: 09: 13.607 ║
╚═══════════════╩═══════════╩═════════════════════ ════╝

Como puede ver, la única forma de asegurarse de que todas las estadísticas se actualicen es actualizar cada una manualmente o actualizar toda la tabla con UPDATE STATISTICS (table);.


@JeremyWeir: como puede ver en el código de ejemplo que acabo de agregar a la pregunta anterior, las únicas estadísticas actualizadas son aquellas actualizadas explícitamente a través de una ALTER INDEX ... REBUILDo una UPDATE STATISTICSdeclaración. Si se reconstruye la tabla, solo se actualizan las estadísticas de índice agrupadas. Para su información, una clave principal y un índice agrupado no son necesariamente compatibles con el mismo objeto de índice.
Max Vernon

5

La página de documentos de Microsoft para las estadísticas de SQL Server dice :

Operaciones como la reconstrucción, la desfragmentación o la reorganización de un índice no cambian la distribución de datos. Por lo tanto, no necesita actualizar las estadísticas después de realizar operaciones ALTER INDEX REBUILD, DBCC DBREINDEX, DBCC INDEXDEFRAG o ALTER INDEX REORGANIZE . El Optimizador de consultas actualiza las estadísticas cuando reconstruye un índice en una tabla o vista con ALTER INDEX REBUILD o DBCC DBREINDEX, sin embargo, esta actualización de estadísticas es un subproducto de volver a crear el índice. Query Optimizer no actualiza las estadísticas después de las operaciones DBCC INDEXDEFRAG o ALTER INDEX REORGANIZE.

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.