У мене є проблема вводу / виводу з великою таблицею.
Загальна статистика
Таблиця має такі основні характеристики:
- середовище: база даних SQL Azure (рівень P4 Premium (500 DTU))
- рядки: 2,135,044,521
- 1,275 використаних розділів
- кластерний та розділений індекс
Модель
Це реалізація таблиці:
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
Розбиття пов'язане з цим:
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', ... )
Якість обслуговування
Я думаю, що індекси та статистика добре підтримуються щовечора шляхом поступового відновлення / реорганізації / оновлення.
Це поточна статистика індексу найбільш використовуваних розділів індексу:
Це поточні властивості статистики найбільш часто використовуваних розділів:
Проблема
Я запускаю простий запит на високій частоті проти таблиці.
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)
План виконання виглядає приблизно так: https://www.brentozar.com/pastetheplan/?id=rJvI_4TtG
Моя проблема полягає в тому, що ці запити призводять до надзвичайно великої кількості операцій вводу / виводу, що призводить до вузького місця PAGEIOLATCH_SH
очікування.
Питання
Я читав, що PAGEIOLATCH_SH
очікування часто пов’язані з недостатньо оптимізованими індексами. Чи є у мене якісь рекомендації щодо зменшення операцій вводу / виводу? Може, додавши кращий індекс?
Відповідь 1 - пов'язана з коментарем від @ S4V1N
План опублікованих запитів був із запиту, який я виконував у SSMS. Після Вашого коментаря я роблю кілька досліджень історії сервера. Запит на точність, який використовується у службі, виглядає дещо інакше (пов'язаний з 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)
Також план виглядає інакше:
https://www.brentozar.com/pastetheplan/?id=H1fhALpKG
або
https://www.brentozar.com/pastetheplan/?id=S1DFQvpKz
І, як ви бачите тут, на цей запит навряд чи впливає наша продуктивність.
Відповідь 2 - пов'язана з відповіддю від @Joe Obbish
Для тестування рішення я замінив Entity Framework простим SqlCommand. Результатом було дивовижне підвищення продуктивності!
План запитів тепер такий же, як у SSMS, і логічне зчитування та записування падає до ~ 8 за виконання.
Загальне падіння навантаження вводу / виводу майже до 0!
Це також пояснює, чому я отримую великий падіння продуктивності після зміни діапазону розділів із щомісячного на щоденний. Відсутність усунення розділів призвело до сканування більшої кількості розділів.