J'ai un problème d'E / S avec une grande table.
Statistiques générales
Le tableau présente les principales caractéristiques suivantes:
- environnement: Azure SQL Database (le niveau est P4 Premium (500 DTU))
- rangées: 2,135,044,521
- 1275 partitions utilisées
- index clusterisé et partitionné
Modèle
Voici l'implémentation de la table:
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
Le partitionnement est lié à ceci:
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é de service
Je pense que les index et les statistiques sont bien entretenus chaque nuit par une reconstruction / réorganisation / mise à jour incrémentielle.
Voici les statistiques d'index actuelles des partitions d'index les plus utilisées:
Voici les propriétés statistiques actuelles des partitions les plus utilisées:
Problème
J'exécute une simple requête sur une haute fréquence contre la table.
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)
Le plan d'exécution ressemble à ceci: https://www.brentozar.com/pastetheplan/?id=rJvI_4TtG
Mon problème est que ces requêtes produisent une quantité extrêmement élevée d'opérations d'E / S entraînant un goulot d'étranglement des PAGEIOLATCH_SH
attentes.
Question
J'ai lu que les PAGEIOLATCH_SH
attentes sont souvent liées à des index mal optimisés. Avez-vous des recommandations à me faire pour réduire les opérations d'E / S? Peut-être en ajoutant un meilleur index?
Réponse 1 - liée au commentaire de @ S4V1N
Le plan de requête publié provenait d'une requête que j'ai exécutée dans SSMS. Après votre commentaire, je fais quelques recherches sur l'historique du serveur. La requête accual extraite du service est un peu différente (liée à 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)
De plus, le plan est différent:
https://www.brentozar.com/pastetheplan/?id=H1fhALpKG
ou
https://www.brentozar.com/pastetheplan/?id=S1DFQvpKz
Et comme vous pouvez le voir ici, nos performances DB ne sont guère influencées par cette requête.
Réponse 2 - liée à la réponse de @Joe Obbish
Pour tester la solution, j'ai remplacé Entity Framework par un simple SqlCommand. Le résultat a été une incroyable amélioration des performances!
Le plan de requête est maintenant le même que dans SSMS et les lectures et écritures logiques tombent à ~ 8 par exécution.
La charge globale d'E / S chute à presque 0!
Cela explique également pourquoi j'obtiens une baisse importante des performances après avoir changé la plage de partition de mensuel à quotidien. L'absence d'élimination de partition a entraîné davantage de partitions à analyser.