Tengo un problema de E / S con una mesa grande.
Estadísticas generales
La tabla tiene las siguientes características principales:
- entorno: Azure SQL Database (el nivel es P4 Premium (500 DTU))
- filas: 2,135,044,521
- 1,275 particiones usadas
- índice agrupado y particionado
Modelo
Esta es la implementación de la tabla:
CREATE TABLE [data].[DemoUnitData](
[UnitID] [bigint] NOT NULL,
[Timestamp] [datetime] NOT NULL,
[Value1] [decimal](18, 2) NULL,
[Value2] [decimal](18, 2) NULL,
[Value3] [decimal](18, 2) NULL,
CONSTRAINT [PK_DemoUnitData] PRIMARY KEY CLUSTERED
(
[UnitID] ASC,
[Timestamp] ASC
)
)
GO
ALTER TABLE [data].[DemoUnitData] WITH NOCHECK ADD CONSTRAINT [FK_DemoUnitData_Unit] FOREIGN KEY([UnitID])
REFERENCES [model].[Unit] ([ID])
GO
ALTER TABLE [data].[DemoUnitData] CHECK CONSTRAINT [FK_DemoUnitData_Unit]
GO
La partición está relacionada con esto:
CREATE PARTITION SCHEME [DailyPartitionSchema] AS PARTITION [DailyPartitionFunction] ALL TO ([PRIMARY])
CREATE PARTITION FUNCTION [DailyPartitionFunction] (datetime) AS RANGE RIGHT
FOR VALUES (N'2017-07-25T00:00:00.000', N'2017-07-26T00:00:00.000', N'2017-07-27T00:00:00.000', ... )
Calidad de servicio
Creo que los índices y las estadísticas se mantienen bien todas las noches mediante la reconstrucción / reorganización / actualización incremental.
Estas son las estadísticas de índice actuales de las particiones de índice más utilizadas:
Estas son las propiedades estadísticas actuales de las particiones más utilizadas:
Problema
Ejecuto una consulta simple en una alta frecuencia contra la tabla.
SELECT [UnitID]
,[Timestamp]
,[Value1]
,[Value2]
,[Value3]
FROM [data].[DemoUnitData]
WHERE [UnitID] = 8877 AND [Timestamp] >= '2018-03-01' AND [Timestamp] < '2018-03-13'
OPTION (MAXDOP 1)
El plan de ejecución se ve así: https://www.brentozar.com/pastetheplan/?id=rJvI_4TtG
Mi problema es que estas consultas producen una cantidad extremadamente alta de operaciones de E / S que resultan en un cuello de botella de PAGEIOLATCH_SH
esperas.
Pregunta
He leído que las PAGEIOLATCH_SH
esperas a menudo están relacionadas con índices no bien optimizados. ¿Hay alguna recomendación que tenga para mí sobre cómo reducir las operaciones de E / S? ¿Quizás agregando un mejor índice?
Respuesta 1 - relacionada con el comentario de @ S4V1N
El plan de consulta publicado fue de una consulta que ejecuté en SSMS. Después de tu comentario, investigo un poco sobre el historial del servidor. La consulta accidental superada por el servicio se ve un poco diferente (EntityFramework relacionado).
(@p__linq__0 bigint,@p__linq__1 datetime2(7),@p__linq__2 datetime2(7))
SELECT 1 AS [C1], [Extent1]
.[Timestamp] AS [Timestamp], [Extent1]
.[Value1] AS [Value1], [Extent1]
.[Value2] AS [Value2], [Extent1]
.[Value3] AS [Value3]
FROM [data].[DemoUnitData] AS [Extent1]
WHERE ([Extent1].[UnitID] = @p__linq__0)
AND ([Extent1].[Timestamp] >= @p__linq__1)
AND ([Extent1].[Timestamp] < @p__linq__2) OPTION (MAXDOP 1)
Además, el plan se ve diferente:
https://www.brentozar.com/pastetheplan/?id=H1fhALpKG
o
https://www.brentozar.com/pastetheplan/?id=S1DFQvpKz
Y como puede ver aquí, nuestro rendimiento de la base de datos apenas está influenciado por esta consulta.
Respuesta 2 - relacionada con la respuesta de @Joe Obbish
Para probar la solución, reemplacé Entity Framework con un simple SqlCommand. ¡El resultado fue un increíble aumento de rendimiento!
El plan de consulta ahora es el mismo que en SSMS y las lecturas y escrituras lógicas caen a ~ 8 por ejecución.
¡La carga general de E / S cae a casi 0!
También explica por qué obtengo una gran caída de rendimiento después de cambiar el rango de partición de mensual a diario. La falta de eliminación de la partición resultó en más particiones para escanear.