如何使我的查询使用可用索引

Zap*_*ica 9 sql-server index-tuning time-series-database

我有以下 SQL 时间序列表:

CREATE TABLE [dbo].[SensorData](
 [DateTimeUtc] [datetime2](2) NOT NULL,
 [SensorId] [int] NOT NULL,
 [Key] [varchar](20) NOT NULL,
 [Value] [decimal](19, 4) NULL,
CONSTRAINT [PK_SensorData] PRIMARY KEY CLUSTERED 
(
  [SensorId] ASC,
  [Key] ASC,
  [DateTimeUtc] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = 
ON, Data_Compression=PAGE) ON PS_Daily(DateTimeUtc))
Run Code Online (Sandbox Code Playgroud)

现在基于这个索引,每个单独的查询都需要在查询where过滤器中包含以下参数:

CREATE TABLE [dbo].[SensorData](
 [DateTimeUtc] [datetime2](2) NOT NULL,
 [SensorId] [int] NOT NULL,
 [Key] [varchar](20) NOT NULL,
 [Value] [decimal](19, 4) NULL,
CONSTRAINT [PK_SensorData] PRIMARY KEY CLUSTERED 
(
  [SensorId] ASC,
  [Key] ASC,
  [DateTimeUtc] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = 
ON, Data_Compression=PAGE) ON PS_Daily(DateTimeUtc))
Run Code Online (Sandbox Code Playgroud)

当查询拥有全部三个时,查询返回的速度非常快。

现在我陷入了一个特定的查询,该查询没有任何特定的值[Key]。例如:

检查过去 12 小时内是否有传感器 1234 的任何数据。在本例中,我们有一个DateTimeSensorId的过滤器值。但这个查询返回速度非常慢。

添加Where [Key] is not null会使 SQL 命中该索引吗?

我知道简单的答案是在表上添加一个新索引,仅使用 [SensorId],[DateTimeUtc]; 但是,这会根据数据库的大小向数据库添加大量空间,并且还会减慢插入速度。

有什么方法可以让上面的查询命中聚集索引吗?

我使用聚集索引键顺序的原因是在阅读了应该如何排序之后,值最唯一的项目应该排在第一位。

我跑了EXEC sp_spaceused [SensorData]

SP_已用空间

询问:

SELECT 
CASE WHEN ( EXISTS (SELECT 
    1 AS [C1]
    FROM [dbo].[SensorData] AS [Extent1]
    WHERE ([Extent1].[DateTimeUtc] > @p__linq__0) AND ([Extent1].[DateTimeUtc] <= @p__linq__1) AND ([Extent1].[SensorId] = @p__linq__2)
)) THEN cast(1 as bit) ELSE cast(0 as bit) END AS [C1]
FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]
Run Code Online (Sandbox Code Playgroud)

SQL计划

每个时间段每个SensorId通常有大约 10 到 40 个不同的键。但显然,我们每天会为每个SensorId存储这 10 到 40 个密钥数千次。

Eva*_*dro 5

您是否考虑过使用 ADX(Azure 数据资源管理器)来存储该表?对于 ADX 来说,此类查询轻而易举。ADX 是 Azure 上的时间序列优化集群。对我来说,这似乎是此类问题的自然解决方案。

它将管理分区、索引,并且您可以自动创建保留策略。

如果您计划使用 Power BI(或 Grafana)使用数据,您还可以在 ADX 上进行直接查询,因此在处理数据模型时无需导入大量数据。此外,ADX 连接器支持非常好的查询折叠,因此,如果您使用 Power BI(例如),视觉效果的查询将即时转换为 Kusto。

如果您的传感器数据来自事件中心或 IoT 中心,您可以将数据直接提取到 ADX(如果它是受支持的文件类型),甚至使用流分析创建自定义反序列化器来提取不同的数据。

如果您需要更多背景信息,请告诉我。


J.D*_*.D. 4

您当前的聚集索引定义(SensorId, Key, DateTimeUtc)将涵盖对所有这三个字段进行谓词的查询。它还应该涵盖使用该定义的任何顺序子集(从左到右阅读)的任何谓词,例如使用SensorId和 的谓词Key,甚至只是使用 的谓词SensorId。这是因为在索引定义中列出字段的顺序就是该索引的 B 树的排序顺序。

在您的情况下,B 树当前按SensorIdthen by排序Key,最后按 排序DateTimeUtc。支持您提到的其他用例的更有用的索引设计是重新排列定义中的列,这样就可以了(DateTimeUtc, SensorId, Key)(如评论中所述)。该单个聚集索引将涵盖您使用所有三个字段进行过滤的用例,并且它支持您只想知道给定传感器的给定日期范围内是否有任何数据的用例。如果您想知道任何给定日期范围内是否有任何数据,它甚至还可以帮助您。

正如评论中所讨论的,如果您计划对 进行范围过滤DateTimeUtc,您可能会发现更好的性能仍然领先于SensorId您使用相等匹配进行过滤的 。但是您仍然可以在聚集索引定义中排列列,因为(SensorId, DateTimeUtc, Key)它涵盖了上述两个用例。

因此,只需重新排列聚集索引定义中的列,您就可以实现您的目标,而无需引入任何新索引,也无需占用任何额外的磁盘空间。

旁注:您可以使用系统存储过程sp_spaceused几乎立即找出给定表有多大(按行和消耗的磁盘大小)。例如EXEC sp_spaceused 'dbo.SensorData';