优化2,135,044,521行表上的索引


10

我有一张大桌子的I / O问题。

一般统计

该表具有以下主要特征:

  • 环境:Azure SQL数据库(层为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

我的问题是这些查询会产生大量的I / O操作,从而导致PAGEIOLATCH_SH等待瓶颈。

顶级等待

我已经读到,PAGEIOLATCH_SH等待通常与未优化索引有关。您对我有什么减少I / O操作的建议吗?也许通过添加更好的索引?


答案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

就像您在这里看到的那样,此查询几乎不会影响我们的数据库性能。

热门SQL

答案2-与@Joe Obbish的答案有关

为了测试解决方案,我用一个简单的SqlCommand替换了Entity Framework。结果是惊人的性能提升!

现在,查询计划与SSMS中的查询计划相同,并且逻辑读取和写入每次执行时下降到〜8。

I / O的总负载几乎降为0! I / O下降

这也解释了为什么将分区范围从每月更改为每天后,性能会大幅下降。缺少分区消除功能导致需要扫描更多分区。


2
从执行计划来看,该查询似乎根本没有问题,它仅扫描读取次数很少的必要分区,并且没有报告pageiolatch_sh等待(sos_sched ..)。这是可以理解的,因为您仍然没有物理读取。那些累积的等待,还是花费了一定的时间?也许问题毕竟是其他一些查询。
S4V1N

我在上方@ S4V1N向您发布了详细的答案
Steffen Mangold

Answers:


7

PAGEIOLATCH_SH如果您能够更改ORM生成的数据类型,则可以减少等待该查询的时间。Timestamp表中的列的数据类型为,DATETIME但参数为@p__linq__1@p__linq__2数据类型为DATETIME2(7)。区别在于,为什么ORM查询的查询计划比您发布的第一个具有硬编码搜索过滤器的查询计划复杂得多。您也可以在XML中获得此提示:

<ScalarOperator ScalarString="GetRangeWithMismatchedTypes([@p__linq__1],NULL,(22))">

照原样,使用ORM查询无法消除任何分区。即使您只是在寻找一天的数据,对于分区函数中定义的每个分区,也将至少获得一些逻辑读取。在每个分区内,您都可以找到索引,因此SQL Server不需要花费很长时间即可移至下一个分区,但是,所有这些IO可能正在累加。

可以肯定,我做了简单的复制。分区功能中定义了11个分区。对于此查询:

DECLARE @p__linq__0 bigint = 2000;
DECLARE @p__linq__1 datetime2(7) = '20180103';
DECLARE @p__linq__2 datetime2(7) = '20180104';

SELECT 1 AS [C1]
, [Extent1].[Timestamp] AS [Timestamp]
, [Extent1].[Value1] AS [Value1]
FROM [DemoUnitData] AS [Extent1]  
WHERE ([Extent1].[UnitID] = @p__linq__0)  
AND ([Extent1].[Timestamp] >= @p__linq__1)  
AND ([Extent1].[Timestamp] < @p__linq__2)
OPTION (MAXDOP 1) ;

IO如下所示:

表'DemoUnitData'。扫描计数11,逻辑读取40

当我修复数据类型时:

DECLARE @p__linq__0 bigint = 2000;
DECLARE @p__linq__1 datetime = '20180103';
DECLARE @p__linq__2 datetime = '20180104';

SELECT 1 AS [C1]
, [Extent1].[Timestamp] AS [Timestamp]
, [Extent1].[Value1] AS [Value1]
FROM [DemoUnitData] AS [Extent1]  
WHERE ([Extent1].[UnitID] = @p__linq__0)  
AND ([Extent1].[Timestamp] >= @p__linq__1)  
AND ([Extent1].[Timestamp] < @p__linq__2)
OPTION (MAXDOP 1) ;

由于消除了分区,IO减少了:

表'DemoUnitData'。扫描计数2,逻辑读取8

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.