Eu tenho um problema de E / S com uma tabela grande.
Estatísticas gerais
A tabela possui as seguintes características principais:
- ambiente: Banco de Dados SQL do Azure (a camada é P4 Premium (500 DTUs))
- linhas: 2.135.044.521
- 1.275 partições usadas
- índice em cluster e particionado
Modelo
Esta é a implementação da tabela:
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
O particionamento está relacionado a isso:
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', ... )
Qualidade de serviço
Eu acho que os índices e as estatísticas são bem mantidos todas as noites por reconstrução / reorganização / atualização incremental.
Estas são as estatísticas atuais do índice das partições de índice mais usadas:
Estas são as propriedades estatísticas atuais das partições mais usadas:
Problema
Eu executo uma consulta simples em alta frequência na tabela.
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)
O plano de execução é assim: https://www.brentozar.com/pastetheplan/?id=rJvI_4TtG
Meu problema é que essas consultas produzem uma quantidade extremamente alta de operações de E / S, resultando em um gargalo de PAGEIOLATCH_SH
esperas.
Questão
Li que as PAGEIOLATCH_SH
esperas geralmente estão relacionadas a índices não otimizados. Há alguma recomendação que você tenha para mim sobre como reduzir as operações de E / S? Talvez adicionando um índice melhor?
Resposta 1 - relacionada ao comentário de @ S4V1N
O plano de consulta publicado era de uma consulta que eu executei no SSMS. Após o seu comentário, faço algumas pesquisas sobre o histórico do servidor. A consulta acumulada excedida do serviço parece um pouco diferente (relacionada ao EntityFramework).
(@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)
Além disso, o plano parece diferente:
https://www.brentozar.com/pastetheplan/?id=H1fhALpKG
ou
https://www.brentozar.com/pastetheplan/?id=S1DFQvpKz
E, como você pode ver aqui, nosso desempenho do banco de dados dificilmente é influenciado por essa consulta.
Resposta 2 - relacionada à resposta de @Joe Obbish
Para testar a solução, substituí o Entity Framework por um SqlCommand simples. O resultado foi um incrível aumento de desempenho!
O plano de consulta agora é o mesmo do SSMS e as leituras e gravações lógicas caem para ~ 8 por execução.
A carga geral de E / S cai para quase 0!
Ele também explica por que recebo uma grande queda no desempenho depois que alterei o intervalo de partições de mensal para diário. A falta de eliminação de partições resultou em mais partições a serem verificadas.