首页 > 解决方案 > 默认情况下(不带 orderby)从分区表中按降序获取数据

问题描述

我正在尝试学习在 SQL Server 中对单个表进行分区并实现https://www.sqlshack.com/database-table-partitioning-sql-server/中给出的示例。

问题:我在名为的表上的分区Reports基于名为 的列ReportDate

当我从分区表中检索记录时,它们总是按升序(默认)排序,ReportDate即使我ReportDate按降序创建了聚集索引。

Select top 10 * 
from Reports

此查询返回如下记录:

2020-01-01
2020-02-01
.
.
.

预期结果:

2020-12-31
2020-11-30
.
.
.

我的默认用例是先获取最新记录,我们可以在分区表中进行吗?如果是,如何?

标签: sql-servertsql

解决方案


ORDER BY省略时没有“默认”顺序。顺序是“未定义的”,因此 SQL Server 可以按照它选择的任何顺序返回行。由于索引、隔离级别、并行性和分区等因素,这种未定义的顺序可能会有所不同。此外,顺序可能因 SQL Server 版本、版本、补丁级别以及风向而异。ORDER BY如果您需要按特定顺序返回的结果,则需要。

话虽如此,琐碎SELECT * FROM Reports查询的实际执行计划揭示了为什么未定义的顺序在有和没有表分区的情况下会有所不同。ReportDate由于READ_COMMITTTED隔离级别,这两个计划都显示访问第一个(并且仅在非分区表的情况下)分区,并返回行并按键顺序(降序)扫描聚集索引。

<RunTimePartitionSummary>
  <PartitionsAccessed PartitionCount="1">
    <PartitionRange Start="1" End="1" />
  </PartitionsAccessed>
</RunTimePartitionSummary>
<IndexScan Ordered="false" ForcedIndex="false" ForceScan="false" NoExpandHint="false" Storage="RowStore">
  <DefinedValues>
    <DefinedValue>
      <ColumnReference Database="[tempdb]" Schema="[dbo]" Table="[Reports]" Column="ReportDate" />
    </DefinedValue>
  </DefinedValues>
  <Object Database="[tempdb]" Schema="[dbo]" Table="[Reports]" Index="[cdx]" IndexKind="Clustered" Storage="RowStore" />
</IndexScan>

但是请注意,分区表的第一个分区仅包含小于或等于第一个分区边界的行(使用RANGE LEFT分区函数)。分区表查询的“未定义”顺序是分区函数边界月份升序后ReportDate降(每个分区内的聚集索引键序列)。

一个重要的旁注是索引策略在有和没有分区的情况下是不同的。分区号在概念上类似于最左边的索引键。在这种情况下,具有所需ORDER BY ReportDate DESC子句和降序索引键的分区表计划不会像人们预期的那样利用降序索引顺序,而是引入了排序运算符(使用 SQL 2019 CU6):

降序索引计划

由于 SQL Server 可以向前和向后遍历 b 树索引,因此没有必要使用单个键创建降序索引。具有升序索引的计划使用更有效的向后扫描来提供排序:

升序计划


推荐阅读