Я храню данные датчика в таблице SensorValues . Таблица и первичный ключ выглядит следующим образом:
CREATE TABLE [dbo].[SensorValues](
[DeviceId] [int] NOT NULL,
[SensorId] [int] NOT NULL,
[SensorValue] [int] NOT NULL,
[Date] [int] NOT NULL,
CONSTRAINT [PK_SensorValues] PRIMARY KEY CLUSTERED
(
[DeviceId] ASC,
[SensorId] ASC,
[Date] DESC
) WITH (
FILLFACTOR=75,
DATA_COMPRESSION = PAGE,
PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF,
IGNORE_DUP_KEY = OFF,
ONLINE = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON)
ON [MyPartitioningScheme]([Date])
Тем не менее, когда я выбираю значение датчика, действительное в течение определенного времени, план выполнения говорит мне, что он выполняет сортировку. Это почему?
Я бы подумал, что, поскольку я храню значения, отсортированные по столбцу Date, сортировка не произойдет. Или потому, что индекс отсортирован не только по столбцу «Дата», т. Е. Он не может предполагать, что результирующий набор отсортирован?
SELECT TOP 1 SensorValue
FROM SensorValues
WHERE SensorId = 53
AND DeviceId = 3819
AND Date < 1339225010
ORDER BY Date DESC
Редактировать: Могу ли я сделать это вместо этого?
Поскольку таблица сортируется DeviceId, SensorId, дата и я делаю SELECT , указав только один DeviceId и один SensorId , набор вывода уже должны быть отсортированы по дате DESC . Поэтому мне интересно, даст ли следующий вопрос одинаковый результат во всех случаях?
SELECT TOP 1 SensorValue
FROM SensorValues
WHERE SensorId = 53
AND DeviceId = 3819
AND Date < 1339225010
Согласно @Catcall ниже, порядок сортировки не совпадает с порядком хранения. Т.е. мы не можем предположить, что возвращаемые значения уже в отсортированном порядке.
Изменить: я попробовал это решение CROSS APPLY, не повезло
@Martin Smith предложил мне попробовать OUTER APPLY применить мой результат к разделам. Я нашел сообщение в блоге ( выровненные некластеризованные индексы на многораздельной таблице ), описывающее подобную проблему, и попытался найти решение, несколько похожее на предложенное Смитом. Однако, не повезло, время выполнения соответствует моему первоначальному решению.
WITH Boundaries(boundary_id)
AS
(
SELECT boundary_id
FROM sys.partition_functions pf
JOIN sys.partition_range_values prf ON pf.function_id = prf.function_id
WHERE pf.name = 'PF'
AND prf.value <= 1339225010
UNION ALL
SELECT max(boundary_id) + 1
FROM sys.partition_functions pf
JOIN sys.partition_range_values prf ON pf.function_id = prf.function_id
WHERE pf.name = 'PF'
AND prf.value <= 1339225010
),
Top1(SensorValue)
AS
(
SELECT TOP 1 d.SensorValue
FROM Boundaries b
CROSS APPLY
(
SELECT TOP 1 SensorValue
FROM SensorValues
WHERE SensorId = 53
AND DeviceId = 3819
AND "Date" < 1339225010
AND $Partition.PF(Date) = b.boundary_id
ORDER BY Date DESC
) d
ORDER BY d.Date DESC
)
SELECT SensorValue
FROM Top1
Ответы:
Для таблицы без разделов я получаю следующий план
Существует один предикат поиска
Seek Keys[1]: Prefix: DeviceId, SensorId = (3819, 53), Start: Date < 1339225010
.Это означает, что SQL Server может выполнить поиск на равенство в первых двух столбцах, а затем начать поиск диапазона, начиная с
1339225010
и упорядочиваяFORWARD
(как определяется индекс[Date] DESC
)TOP
Оператор прекратит больше строк запроса от искать после того, как первый ряд испускается.Когда я создаю схему и функцию разбиения
И заполните таблицу следующими данными
План на SQL Server 2008 выглядит следующим образом.
Фактическое количество строк, выбрасываемых из поиска, равно
500
. План показывает предикаты поискаУказывая, что используется подход пропуска сканирования, описанный здесь
Этот план представляет собой последовательный план, и поэтому для конкретного имеющегося у вас запроса кажется, что, если SQL Server обеспечит обработку разделов в порядке убывания
date
, исходный план с этимTOP
все равно будет работать, и он мог бы прекратить обработку после того, как первая соответствующая строка была найдено вместо продолжения и выдачи оставшихся 499 совпадений.На самом деле план на 2005 год выглядит так, как будто он использует такой подход
Я не уверен , если это прямо вперед , чтобы получить тот же план на 2008 или , может быть , понадобилась бы
OUTER APPLY
наsys.partition_range_values
имитировать его.источник
Многие люди считают, что кластерный индекс гарантирует порядок сортировки на выходе. Но это не то, что он делает; это гарантирует порядок хранения на диске.
Смотрите, например, этот пост в блоге и это более продолжительное обсуждение .
источник
Я предполагаю, что СОРТ необходим из-за параллельного плана. Я основываю это на какой-то смутной и далекой статье в блоге: но я нашел это на MSDN, что может или не может оправдать это
Итак, попробуйте с MAXDOP 1 и посмотрите, что произойдет ...
Также намекает на сообщение в блоге @sql kiwi о Simple Talk в разделе «Оператор обмена». И "DOP зависимость" здесь
источник
date
. Теперь у меня есть и, кажется, разделение является виновником 2005 года, возможно, ведет себя лучше для этого конкретного запроса.В принципе вы правы - поскольку первичный ключ имеет порядок «DeviceId, SensorId, Date», данные в ключе не отсортированы по дате, поэтому не могут быть использованы. Если бы ваш ключ был в другом порядке «Дата, Идентификатор устройства, Сенсорный идентификатор», то данные в ключе будут отсортированы по дате, поэтому их можно использовать ...
источник