Ho un problema I / O con una tabella di grandi dimensioni.
Statistiche generali
La tabella presenta le seguenti caratteristiche principali:
- ambiente: Database SQL di Azure (il livello è P4 Premium (500 DTU))
- righe: 2.135.044.521
- 1.275 partizioni utilizzate
- indice cluster e partizionato
Modello
Questa è l'implementazione della tabella:
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
Il partizionamento è correlato a questo:
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', ... )
Qualità del servizio
Penso che gli indici e le statistiche siano ben mantenute ogni notte da ricostruzioni / riorganizzazioni / aggiornamenti incrementali.
Queste sono le statistiche dell'indice corrente delle partizioni di indice più utilizzate:
Queste sono le proprietà statistiche attuali delle partizioni più utilizzate:
Problema
Eseguo una semplice query su una frequenza elevata rispetto al tavolo.
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)
Il piano di esecuzione è simile al seguente: https://www.brentozar.com/pastetheplan/?id=rJvI_4TtG
Il mio problema è che queste query producono una quantità estremamente elevata di operazioni I / O con conseguente collo di bottiglia delle PAGEIOLATCH_SH
attese.
Domanda
Ho letto che le PAGEIOLATCH_SH
attese sono spesso correlate a indici non ottimizzati. Ci sono dei consigli per me su come ridurre le operazioni di I / O? Forse aggiungendo un indice migliore?
Risposta 1 - correlata al commento di @ S4V1N
Il piano di query pubblicato proveniva da una query eseguita in SSMS. Dopo il tuo commento, faccio alcune ricerche sulla storia del server. La query accidentale eseguita dal servizio appare leggermente diversa (relativa a 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)
Inoltre, il piano sembra diverso:
https://www.brentozar.com/pastetheplan/?id=H1fhALpKG
o
https://www.brentozar.com/pastetheplan/?id=S1DFQvpKz
E come puoi vedere qui, le nostre prestazioni del DB non sono influenzate da questa query.
Risposta 2: correlata alla risposta di @Joe Obbish
Per testare la soluzione ho sostituito Entity Framework con un semplice SqlCommand. Il risultato è stato un incredibile aumento delle prestazioni!
Il piano di query è ora lo stesso di SSMS e le letture e le scritture logiche scendono a ~ 8 per esecuzione.
Il carico I / O complessivo scende a quasi 0!
Spiega anche perché ottengo un forte calo delle prestazioni dopo aver modificato l'intervallo di partizioni da mensile a giornaliero. La mancanza dell'eliminazione delle partizioni ha comportato la scansione di più partizioni.