snippetsqlModerate
Sort order specified in primary key, yet sorting is executed on SELECT
Viewed 0 times
sortingorderprimaryspecifiedselectyetexecutedsortkey
Problem
I'm storing sensor data in a table SensorValues. The table and primary key is as follows:
Yet, when I select the sensor value valid for a specific time the execution plan tells me it is doing a sort. Why is that?
I would have thought that since I store the values sorted by the Date column, the sorting would not occure. Or is it because the index isn't solely sorted by the Date column, i.e. it can't assume that the result set is sorted?
Edit: Can I do this instead?
Since the table is sorted DeviceId, SensorId, Date and I do a SELECT specifying only one DeviceId and one SensorId, the output set should already be sorted by Date DESC. So I wonder if the following question would yield the same result in all cases?
According to @Catcall below, the sort order is not the same as the storage order. I.e. we can't assume that the returned values are already in a sorted order.
Edit: I've tried this CROSS APPLY solution, no luck
@Martin Smith suggested I'd try to OUTER APPLY my result against the partitions. I found a blog post (Aligned non-clustered indexes on partitioned table) describing this similar problem and tried the somewhat similar solution to what Smith suggested. Howev
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])Yet, when I select the sensor value valid for a specific time the execution plan tells me it is doing a sort. Why is that?
I would have thought that since I store the values sorted by the Date column, the sorting would not occure. Or is it because the index isn't solely sorted by the Date column, i.e. it can't assume that the result set is sorted?
SELECT TOP 1 SensorValue
FROM SensorValues
WHERE SensorId = 53
AND DeviceId = 3819
AND Date < 1339225010
ORDER BY Date DESCEdit: Can I do this instead?
Since the table is sorted DeviceId, SensorId, Date and I do a SELECT specifying only one DeviceId and one SensorId, the output set should already be sorted by Date DESC. So I wonder if the following question would yield the same result in all cases?
SELECT TOP 1 SensorValue
FROM SensorValues
WHERE SensorId = 53
AND DeviceId = 3819
AND Date < 1339225010According to @Catcall below, the sort order is not the same as the storage order. I.e. we can't assume that the returned values are already in a sorted order.
Edit: I've tried this CROSS APPLY solution, no luck
@Martin Smith suggested I'd try to OUTER APPLY my result against the partitions. I found a blog post (Aligned non-clustered indexes on partitioned table) describing this similar problem and tried the somewhat similar solution to what Smith suggested. Howev
Solution
For a non partitioned table I get the following plan
There is a single seek predicate on
Meaning that SQL Server can perform an equality seek on the first two columns and then begin a range seek starting at
The
When I create the partition scheme and function
And populate the table with the following data
The plan on SQL Server 2008 looks as follows.
The actual number of rows emitted from the seek is
Indicating it is using the skip scan approach described here
the query optimizer is extended so that a seek or scan operation with
one condition can be done on PartitionID (as the logical leading
column) and possibly other index key columns, and then a second-level
seek, with a different condition, can be done on one or more
additional columns, for each distinct value that meets the
qualification for the first-level seek operation.
This plan is a serial plan and so for the specific query you have it seems that if SQL Server ensured that it processed the partitions in descending order of
In fact the plan on 2005 looks like it does take that approach
I'm not sure if it is straight forward to get the same plan on 2008 or maybe it would need an
There is a single seek predicate on
Seek Keys[1]: Prefix: DeviceId, SensorId = (3819, 53), Start: Date < 1339225010. Meaning that SQL Server can perform an equality seek on the first two columns and then begin a range seek starting at
1339225010 and ordered FORWARD (as the index is defined with [Date] DESC)The
TOP operator will stop requesting more rows from the seek after the first row is emitted.When I create the partition scheme and function
CREATE PARTITION FUNCTION PF (int)
AS RANGE LEFT FOR VALUES (1000, 1339225009 ,1339225010 , 1339225011);
GO
CREATE PARTITION SCHEME [MyPartitioningScheme]
AS PARTITION PF
ALL TO ([PRIMARY] );And populate the table with the following data
INSERT INTO [dbo].[SensorValues]
/*500 rows matching date and SensorId, DeviceId predicate*/
SELECT TOP (500) 3819,53,1, ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM master..spt_values
UNION ALL
/*700 rows matching date but not SensorId, DeviceId predicate*/
SELECT TOP (700) 3819,52,1, ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM master..spt_values
UNION ALL
/*1100 rows matching SensorId, DeviceId predicate but not date */
SELECT TOP (1100) 3819,53,1, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) + 1339225011
FROM master..spt_valuesThe plan on SQL Server 2008 looks as follows.
The actual number of rows emitted from the seek is
500. The plan shows seek predicatesSeek Keys[1]: Start: PtnId1000 = 1,
Seek Keys[2]: Prefix: DeviceId, SensorId = (3819, 53), Start: Date < 1339225010Indicating it is using the skip scan approach described here
the query optimizer is extended so that a seek or scan operation with
one condition can be done on PartitionID (as the logical leading
column) and possibly other index key columns, and then a second-level
seek, with a different condition, can be done on one or more
additional columns, for each distinct value that meets the
qualification for the first-level seek operation.
This plan is a serial plan and so for the specific query you have it seems that if SQL Server ensured that it processed the partitions in descending order of
date that the original plan with the TOP would still work and it could stop processing after the first matching row was found rather than continuing on and outputting the remaining 499 matches.In fact the plan on 2005 looks like it does take that approach
I'm not sure if it is straight forward to get the same plan on 2008 or maybe it would need an
OUTER APPLY on sys.partition_range_values to simulate it.Code Snippets
CREATE PARTITION FUNCTION PF (int)
AS RANGE LEFT FOR VALUES (1000, 1339225009 ,1339225010 , 1339225011);
GO
CREATE PARTITION SCHEME [MyPartitioningScheme]
AS PARTITION PF
ALL TO ([PRIMARY] );INSERT INTO [dbo].[SensorValues]
/*500 rows matching date and SensorId, DeviceId predicate*/
SELECT TOP (500) 3819,53,1, ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM master..spt_values
UNION ALL
/*700 rows matching date but not SensorId, DeviceId predicate*/
SELECT TOP (700) 3819,52,1, ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM master..spt_values
UNION ALL
/*1100 rows matching SensorId, DeviceId predicate but not date */
SELECT TOP (1100) 3819,53,1, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) + 1339225011
FROM master..spt_valuesSeek Keys[1]: Start: PtnId1000 <= 2, End: PtnId1000 >= 1,
Seek Keys[2]: Prefix: DeviceId, SensorId = (3819, 53), Start: Date < 1339225010Context
StackExchange Database Administrators Q#19159, answer score: 13
Revisions (0)
No revisions yet.