По умолчанию извлекает данные в порядке убывания (без orderby) из секционированной таблицы

#sql-server #tsql

#sql-server #tsql

Вопрос:

Я пытаюсь научиться разбивать одну таблицу на разделы в 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
.
.
.
  

Мой вариант использования по умолчанию — сначала извлекать последние записи, можем ли мы сделать это в секционированной таблице? Если да, то каким образом?

Ответ №1:

Порядок «по умолчанию», когда 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-дерева как в прямом, так и в обратном направлении, нет необходимости создавать индексы по убыванию с помощью одного ключа. План с возрастающим индексом использует более эффективное обратное сканирование для обеспечения упорядоченности:

планируйте с возрастающим индексом

Ответ №2:

На это нельзя полагаться! Если вы не укажете order by предложение, то у вас нет гарантированного порядка результатов. Так что просто добавьте это в свой запрос в любом случае.

 select top 10 * from Reports order by ReportDate desc
  

Комментарии:

1. Понятно, просто любопытно, почему записи не поступают в порядке убывания даже после размещения индекса кластера в порядке убывания, как в несекционированной таблице.

2. Они не «приходят по порядку». Порядок не определен и будет определяться условиями выполнения, планом выполнения, страницами в памяти, страницами, которые необходимо перенести в память, объемом доступной памяти и т.д. Если вам нужен порядок в результирующем наборе, единственный способ гарантировать это — с помощью предложения order by . Аналогично использованию «top 10», вернет 10 строк no и в произвольном порядке.