#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 и в произвольном порядке.