为什么从组合索引DESC中选择top 1也用于按月分区而不选择top值?

Adr*_*ger 2 index sql-server

我们有非常大的数据库表,我需要选择最大 id 的值。鉴于表大小 SELECT MAX(id) FROM tableA 不会表现得足够好。

表定义(为了清楚起见省略了列)

CREATE TABLE [dbo].[TableA](
    [id] [numeric](19, 0) NOT NULL,
    [timeSampled] [datetime] NOT NULL
 CONSTRAINT [PK_TableA] PRIMARY KEY NONCLUSTERED 
(
    [id] DESC,
    [timeSampled] DESC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
Run Code Online (Sandbox Code Playgroud)

该表在 timesampled 上按月分区,并且因为我们将分区切换到另一个表以存档数据,timeSampled 列必须包含在主键中。

所以,PK是

[id] DESC,
[timeSampled] DESC
Run Code Online (Sandbox Code Playgroud)

该表包含 2013 年 5 月和 2013 年 6 月的行,id 以日期顺序递增(即最大 id 为 6 月)

当我从表中选择前 1 个 id 时,如下所示

SELECT top 1 id
FROM dbo.TableA
WITH (INDEX (PK_TableA)) 
Run Code Online (Sandbox Code Playgroud)

我没有得到最大 id,而是从 May 得到最大 id(即 May 分区中的最后一个条目)。

任何想法为什么会这样?基本上似乎是从一个分区中选择 MAX id,而不是所有分区中的 max

Pau*_*ite 6

基本上似乎是从一个分区中选择 MAX id,而不是所有分区中的 max

写入TOP (1)没有ORDER BY子句定义哪一行是“顶部”是指查询处理器在逻辑上是自由地返回任何从该组行。优化器选择的查询计划恰好返回一个特定的行(第一个分区的最高 id),但您不能依赖它,即使它是一个有用的结果。

每当您使用时,TOP您应该始终ORDER BY在相同范围内指定一个以产生确定性行为 - 除非您真的不关心返回哪些行。

鉴于表大小 SELECT MAX(id) FROM tableA 不会表现得足够好

优化器缺乏将分区索引上的标量MAXMIN聚合转换为每个分区聚合上的全局聚合的逻辑。Itzik Ben-Gan 在本文中解释了限制并提供了一般解决方法。

如果已知最高分区号并保证不会更改,则使用该$partition函数指定文字分区的解决方法将起作用,尽管如果将来分区策略发生更改,它可能会以不明显的方式失败。

这种“解决方案”的工作原理是消除除一个分区之外的所有分区,从而对索引的一个分区进行简单的查找。

由于某种原因,按 id 添加订单不会提高性能

相同的优化器限制广泛适用于TOP (1) ... ORDER BY. 这ORDER BY使结果具有确定性,但在这种特殊情况下无助于产生更有效的计划(但见下文)。

隐式索引键

您的索引位于id DESC, timeSampled DESC。在 SQL Server 2008 及更高版本中,分区引入了一个额外的隐含前导$partition ASC(它总是升序,它不可配置)制作完整索引键$partition ASC, id DESC, timeSampled DESC

由于idtimeSampled一起增加(尽管架构中没有任何内容可以保证这一点),您可以将查询重写为TOP (1) ... ORDER BY $partition DESC, id DESC. 不幸的是,DESC索引上的键和ASC隐含的前导键$partition意味着索引不能用于按顺序扫描索引中的一行。

如果您的索引键改为,id ASC, timeSampled ASC则整个索引键将是$partition ASC, id ASC, timeSampled ASC. 这个全ASC索引可以向后扫描,只返回键顺序的第一行。该行将保证id在编号最高的分区中具有最高值。给定 id 和分区 id 之间的(非强制)关系,这将产生正确的结果,并使用仅读取一行的最佳执行计划。

此“解决方案”缺乏完整性,因为未强制执行 id-timeSampled 关系,而且您可能无论如何都不想重建非聚集主键。尽管如此,我还是提到了它,因为它可以增强您对分区如何与索引交互的理解。