Tenemos una gran base de datos particionada de SQL Server que utiliza estadísticas incrementales. Todos los índices están alineados con particiones. Cuando intentamos reconstruir una partición en línea por partición, todas las estadísticas desaparecen después de que se reconstruye el índice.
A continuación se muestra un script para replicar el problema en SQL Server 2014 con la base de datos AdventureWorks2014.
--Example against AdventureWorks2014 Database
CREATE PARTITION FUNCTION TransactionRangePF1 (DATETIME)
AS RANGE RIGHT FOR VALUES
(
'20130501', '20130601', '20130701', '20130801',
'20130901', '20131001', '20131101', '20131201',
'20140101', '20140201', '20140301'
);
GO
CREATE PARTITION SCHEME TransactionsPS1 AS PARTITION TransactionRangePF1 TO
(
[PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY],
[PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY],
[PRIMARY], [PRIMARY], [PRIMARY]
);
GO
CREATE TABLE dbo.TransactionHistory
(
TransactionID INT NOT NULL, -- not bothering with IDENTITY here
ProductID INT NOT NULL,
ReferenceOrderID INT NOT NULL,
ReferenceOrderLineID INT NOT NULL DEFAULT (0),
TransactionDate DATETIME NOT NULL DEFAULT (GETDATE()),
TransactionType NCHAR(1) NOT NULL,
Quantity INT NOT NULL,
ActualCost MONEY NOT NULL,
ModifiedDate DATETIME NOT NULL DEFAULT (GETDATE()),
CONSTRAINT CK_TransactionType
CHECK (UPPER(TransactionType) IN (N'W', N'S', N'P'))
)
ON TransactionsPS1 (TransactionDate);
INSERT INTO dbo.TransactionHistory
SELECT * FROM Production.TransactionHistory
-- SELECT * FROM sys.partitions
-- WHERE object_id = OBJECT_ID('dbo.TransactionHistory');
CREATE NONCLUSTERED INDEX IDX_ProductId ON dbo.TransactionHistory (ProductId)
WITH (DATA_COMPRESSION = ROW, STATISTICS_INCREMENTAL=ON)
ON TransactionsPS1 (TransactionDate)
DBCC SHOW_STATISTICS('dbo.TransactionHistory', IDX_ProductId);
PRINT 'Stats are avialable'
ALTER INDEX [IDX_ProductId] ON [dbo].[TransactionHistory] REBUILD
PARTITION = 9 WITH (ONLINE = ON , DATA_COMPRESSION = ROW)
PRINT 'After online index rebuild by partition stats are now gone'
DBCC SHOW_STATISTICS('dbo.TransactionHistory', IDX_ProductId);
PRINT 'Rebuild the stats with a rebuild for all paritions (this works)'
ALTER INDEX [IDX_ProductId] ON [dbo].[TransactionHistory] REBUILD
PARTITION = ALL WITH (ONLINE = ON , DATA_COMPRESSION = ROW,
STATISTICS_INCREMENTAL = ON)
PRINT 'Stats are back'
DBCC SHOW_STATISTICS('dbo.TransactionHistory', IDX_ProductId);
PRINT 'Works correctly for an offline rebuild by partition'
ALTER INDEX [IDX_ProductId] ON [dbo].[TransactionHistory] REBUILD
PARTITION = 9 WITH (ONLINE = OFF , DATA_COMPRESSION = ROW)
--stats still there
DBCC SHOW_STATISTICS('dbo.TransactionHistory', IDX_ProductId);
ALTER INDEX [IDX_ProductId] ON [dbo].[TransactionHistory] REBUILD
PARTITION = 9 WITH (ONLINE = ON , DATA_COMPRESSION = ROW)
DBCC SHOW_STATISTICS('dbo.TransactionHistory', IDX_ProductId);
PRINT' stats are gone!!!!!!'
Como se muestra, no podemos reconstruir índices por partición en línea sin perder todas las estadísticas del índice. Este es un problema de mantenimiento importante para nosotros. Casi parece que la opción incremental de estadísticas debe ser parte de la sintaxis de reconstrucción de índice único o la opción en línea debe manejarla correctamente como lo hace la opción fuera de línea.
Por favor, avíseme si me falta algo.
Actualizaciones:
En cuanto a nuestra necesidad de estadísticas incrementales: estamos particionando en una identificación de cliente interna y no en una fecha. Entonces, cuando ingresa un nuevo cliente (gran carga de datos), simplemente podemos actualizar las estadísticas de la partición y evitar rápidamente que se creen planes feos para este nuevo cliente. Creo que lo archivaré con Microsoft como un error y veré lo que tienen que decir e iré con la solución de simplemente volver a muestrear las estadísticas para esa partición.
Informe de error de conexión:
Actualización: Microsoft ha confirmado que es un error.
Respuestas:
No estoy seguro de si es un error, per se, pero definitivamente es un hecho interesante. Las reconstrucciones de particiones en línea son nuevas en SQL Server 2014, por lo que puede haber algunas partes internas para resolver esto.
Aquí está mi mejor explicación para ti. Las estadísticas incrementales requieren que todas las particiones se muestreen a la misma velocidad, de modo que cuando el motor fusiona las páginas de estadísticas, puede estar seguro de que la distribución muestreada es comparable.
REBUILD
necesariamente muestrea datos a una frecuencia de muestreo del 100%. No hay garantía de que la frecuencia de muestreo del 100% en la partición 9 siempre sea la frecuencia de muestreo exacta del resto de las particiones. Debido a esto, parece que el motor no puede fusionar las muestras y terminas con un blob de estadísticas vacío. Sin embargo, el objeto de estadísticas sigue ahí:Puede llenar el blob a través de cualquier cantidad de medios:
UPDATE STATISTICS dbo.TransactionHistory (IDX_ProductId) WITH RESAMPLE;
o
UPDATE STATISTICS dbo.TransactionHistory (IDX_ProductId) WITH RESAMPLE ON PARTITIONS (9);
o puede esperar a que AutoStats se actualice en la primera compilación de un plan de consulta con ese objeto:
Habiendo dicho todo eso, esta publicación esclarecedora de Erin Stellato destaca lo que se percibe como una deficiencia importante de las estadísticas incrementales. El optimizador no utiliza sus datos a nivel de partición en la generación del plan de consulta, lo que reduce el supuesto beneficio de las estadísticas incrementales. ¿Cuál es, entonces, el beneficio actual de las estadísticas incrementales? Diría que su utilidad principal es la capacidad de muestrear tablas grandes de manera más consistente a una tasa más alta que con las estadísticas tradicionales.
Usando su ejemplo, así es como se ven las cosas:
Una actualización de estadísticas de exploración completa sobre los costos estadísticos incrementales de 131 ms. Una actualización de estadísticas de exploración completa en la estadística sin alineación de partición cuesta 66 ms. La estadística no alineada es más lenta probablemente debido a la sobrecarga incurrida al fusionar las páginas de estadísticas individuales nuevamente en el histograma principal. Sin embargo, usando el objeto estadístico alineado con la partición, podemos actualizar una partición y fusionarla nuevamente en el blob de histograma principal en 5 ms. Entonces, en este punto, el administrador con la estadística incremental se enfrenta a una decisión. Pueden disminuir el tiempo general de mantenimiento de las estadísticas solo actualizando las particiones que tradicionalmente tendrían que actualizarse, o pueden experimentar con frecuencias de muestreo más altas de modo que potencialmente obtengan más filas muestreadas en el mismo período de tiempo que su período de mantenimiento anterior. El primero permite respirar en la ventana de mantenimiento, el segundo puede llevar las estadísticas en una tabla muy grande a un lugar donde las consultas obtengan mejores planes basados en estadísticas más precisas. Esto no es una garantía y su kilometraje puede variar.
El lector puede ver que 66 ms no es un tiempo de actualización de estadísticas doloroso en esta tabla, así que intenté configurar una prueba en el conjunto de datos de stackexchange. Hay 6.418.608 publicaciones (excluyendo las publicaciones de StackOverflow y todas las publicaciones de 2012, un error de datos por mi parte) en el volcado reciente que descargué.
He particionado los datos por
[CreationDate]
... demo.Aquí hay algunos tiempos para algunos escenarios bastante estándar (100% - reconstrucción de índice, predeterminado - actualización automática de estadísticas o
UPDATE STATISTICS
sin una frecuencia de muestreo especificada:Supongamos que somos más sofisticados que estos escenarios predeterminados y hemos decidido que una tasa de muestra del 10% es la tasa mínima que debería proporcionarnos los planes que necesitamos y al mismo tiempo mantener el tiempo de mantenimiento en un plazo razonable.
Hasta ahora no hay un beneficio claro de tener una estadística incremental. Sin embargo, si aprovechamos el DMV indocumentado
sys.dm_db_stats_properties_internal()
(a continuación), puede obtener una idea de qué partición (es) desea actualizar. Digamos que hicimos cambios en los datos en la partición 3 y queremos asegurarnos de que las estadísticas estén actualizadas para las consultas entrantes. Aquí están nuestras opciones:Aquí es donde debemos tomar una decisión. ¿Nos llevamos la victoria de un 63 ms. actualización de estadísticas basada en particiones, ¿o aumentamos aún más la frecuencia de muestreo? Digamos que estamos dispuestos a tomar el golpe inicial de muestreo al 50% en una estadística incremental:
Podemos muestrear muchos más datos, tal vez configurando el optimizador para hacer mejores conjeturas sobre nuestros datos (aunque todavía no está usando estadísticas a nivel de partición) y podemos hacerlo más rápido ahora que tenemos estadísticas incrementales
Sin embargo, una última cosa divertida para resolver. ¿Qué pasa con las actualizaciones de estadísticas sincrónicas? ¿Se conserva la frecuencia de muestreo del 50% incluso cuando se inician los autostats?
Eliminé datos de la partición 3 y ejecuté una consulta en CreationDate y verifiqué y luego verifiqué las tasas con la misma consulta a continuación. La tasa de muestra del 50% se conservó.
Entonces, en resumen: las estadísticas incrementales pueden ser una herramienta útil con la cantidad correcta de pensamiento y el trabajo de configuración inicial. Sin embargo, debe conocer el problema que está tratando de resolver y luego debe resolverlo adecuadamente. Si obtiene estimaciones de cardinalidad incorrectas, es posible que pueda obtener mejores planes con una tasa de muestreo estratégica y alguna intervención invertida. Sin embargo, solo está obteniendo una pequeña porción del beneficio ya que el histograma que se usa es la página de estadísticas combinadas y no la información de nivel de partición. Si siente dolor en su ventana de mantenimiento, entonces quizás las estadísticas incrementales pueden ayudarlo, pero probablemente requerirá que configure un proceso de intervención de mantenimiento de alto contacto. Independientemente,:
Espero que esto ayude
fuente