Büyük bir tablo ile bir G / Ç sorunum var.
Genel istatistikler
Tablo aşağıdaki ana özelliklere sahiptir:
- çevre: Azure SQL Veritabanı (katman P4 Premium (500 DTU))
- satırlar: 2,135,044,521
- 1.275 bölümler kullanılmış
- kümelenmiş ve bölümlenmiş dizin
model
Bu tablo uygulamasıdır:
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
Bölümleme bununla ilgilidir:
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', ... )
Hizmet kalitesi
Sanırım endeksler ve istatistikler her gece artımlı yeniden oluşturma / yeniden düzenleme / güncelleme ile korunur.
Bunlar, en yoğun kullanılan dizin bölümlerinin geçerli dizin istatistikleridir:
Bunlar en çok kullanılan bölümlerin güncel istatistik özellikleridir:
Sorun
Tablo karşı yüksek bir frekans üzerinde basit bir sorgu çalıştırın.
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)
Yürütme planı şuna benzer: https://www.brentozar.com/pastetheplan/?id=rJvI_4TtG
Benim sorunum, bu sorgular son derece yüksek miktarda I / O işlemleri üretmek PAGEIOLATCH_SH
bekler darboğaz ile sonuçlanır .
Soru
PAGEIOLATCH_SH
Beklemelerin genellikle iyi optimize edilmemiş dizinlerle ilişkili olduğunu okudum . G / Ç işlemlerini nasıl azaltabileceğime dair önerileriniz var mı? Belki daha iyi bir dizin ekleyerek?
Cevap 1 - @ S4V1N'den gelen yorumla ilgili
Gönderilen sorgu planı SSMS'de yürüttüğüm bir sorgudan alındı. Yorumunuzdan sonra sunucu geçmişi hakkında biraz araştırma yapıyorum. Hizmetten istisnalı sorgu biraz farklı görünüyor (EntityFramework ile ilgili).
(@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)
Ayrıca, plan farklı görünüyor:
https://www.brentozar.com/pastetheplan/?id=H1fhALpKG
veya
https://www.brentozar.com/pastetheplan/?id=S1DFQvpKz
Burada da görebileceğiniz gibi, DB performansımız bu sorgudan pek etkilenmiyor.
Cevap 2 - @Joe Obbish'in cevabı ile ilgili
Çözümü test etmek için Entity Framework'ü basit bir SqlCommand ile değiştirdim. Sonuç inanılmaz bir performans artışı oldu!
Sorgu planı şimdi SSMS ile aynıdır ve mantıksal okuma ve yazma işlemleri yürütme başına ~ 8'e düşer.
Toplam I / O yükü neredeyse 0'a düşüyor!
Ayrıca, bölüm aralığını aylıktan günlük olarak değiştirdikten sonra neden büyük bir performans düşüşü aldığımı da açıklıyor. Bölüm ortadan kaldırılması daha fazla bölümün taranmasına neden oldu.