Saya memiliki masalah I / O dengan meja besar.
Statistik umum
Tabel ini memiliki karakteristik utama berikut:
- lingkungan: Azure SQL Database (tingkatnya adalah P4 Premium (500 DTUs))
- baris: 2.135.044.521
- 1.275 partisi yang digunakan
- indeks berkerumun dan dipartisi
Model
Ini adalah implementasi tabel:
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
Partisi terkait dengan ini:
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', ... )
Kualitas pelayanan
Saya pikir indeks dan statistik dipelihara dengan baik setiap malam dengan penambahan membangun kembali / mengatur ulang / memperbarui.
Ini adalah statistik indeks saat ini dari partisi indeks yang paling banyak digunakan:
Ini adalah properti statistik saat ini dari partisi yang paling banyak digunakan:
Masalah
Saya menjalankan kueri sederhana pada frekuensi tinggi terhadap tabel.
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)
Rencana eksekusi terlihat seperti ini: https://www.brentozar.com/pastetheplan/?id=rJvI_4TtG
Masalah saya adalah bahwa kueri ini menghasilkan jumlah operasi I / O yang sangat tinggi yang mengakibatkan kemacetan PAGEIOLATCH_SH
menunggu.
Pertanyaan
Saya telah membaca bahwa PAGEIOLATCH_SH
menunggu seringkali terkait dengan indeks yang tidak dioptimalkan dengan baik. Apakah ada rekomendasi yang Anda miliki untuk saya bagaimana mengurangi operasi I / O? Mungkin dengan menambahkan indeks yang lebih baik?
Jawaban 1 - terkait dengan komentar dari @ S4V1N
Paket kueri yang diposkan berasal dari kueri yang saya jalankan di SSMS. Setelah komentar Anda, saya melakukan riset tentang sejarah server. Kueri aktual yang dikecualikan dari layanan terlihat sedikit berbeda (terkait 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)
Juga, rencananya terlihat berbeda:
https://www.brentozar.com/pastetheplan/?id=H1fhALpKG
atau
https://www.brentozar.com/pastetheplan/?id=S1DFQvpKz
Dan seperti yang Anda lihat di sini, kinerja DB kami hampir tidak dipengaruhi oleh permintaan ini.
Jawaban 2 - terkait dengan jawaban dari @ Jo Obbish
Untuk menguji solusi saya mengganti Entity Framework dengan SqlCommand sederhana. Hasilnya adalah peningkatan kinerja yang luar biasa!
Rencana kueri sekarang sama seperti di SSMS dan logis membaca dan menulis turun ke ~ 8 per eksekusi.
Penurunan beban I / O keseluruhan menjadi hampir 0!
Ini juga menjelaskan mengapa saya mendapatkan penurunan kinerja besar setelah saya mengubah rentang partisi dari bulanan ke harian. Hilangnya penghapusan partisi mengakibatkan lebih banyak partisi untuk memindai.