即使数据按索引排序,执行计划也包含“排序”

And*_*son 5 sql-server azure-sql-database

我有一个表,它有一个聚集索引,如下所示:

CREATE CLUSTERED INDEX [IX_MachineryId_DateRecorded]
ON Machinery (MachineryId, DateRecorded)
Run Code Online (Sandbox Code Playgroud)

我根据聚集索引中的字段进行选择,再加上一个:

SELECT DateRecorded, Latitude, Longitude
FROM MachineryReading
WHERE MachineryId = 2127        -- First key in the index
AND DateRecorded > '2017-01-10' -- Second key in the index
AND DateRecorded < '2017-10-16' -- Second key in the index
AND FixStatus >= 2              -- Not a key, resulting in a scan
ORDER BY DateRecorded
Run Code Online (Sandbox Code Playgroud)

我原以为这会导致一个简单的聚集索引扫描。但是,查看实时查询统计信息和实际执行计划,查询的大部分执行时间来自对索引扫描后的结果进行排序。为什么排序后的数据又被排序了?

https://www.brentozar.com/pastetheplan/?id=S10DvjZpb

Mar*_*ith 6

您的查询访问 10 个分区并且您正在搜索 10 个月的范围,所以我猜它是在DateRecorded.

我可以用下面的排序重现你的计划。

CREATE PARTITION FUNCTION pf1 (DATE) AS RANGE RIGHT FOR VALUES ( 
'2017-01-01', 
'2017-02-01', 
'2017-03-01', 
'2017-04-01', 
'2017-05-01', 
'2017-06-01', 
'2017-07-01', 
'2017-08-01', 
'2017-09-01', 
'2017-10-01', 
'2017-11-01' );

CREATE PARTITION SCHEME ps1 AS PARTITION pf1 ALL TO ([Primary]);

CREATE TABLE MachineryReading
  (
     MachineryId  INT,
     DateRecorded DATE,
     Latitude     FLOAT,
     Longitude    FLOAT,
     FixStatus    INT
  )
ON ps1(DateRecorded)

CREATE CLUSTERED INDEX [IX_MachineryId_DateRecorded]
  ON MachineryReading (MachineryId, DateRecorded)
Run Code Online (Sandbox Code Playgroud)

但从技术上讲,如果您可以获得一个按顺序处理分区并将一个有序结果连接到下一个的计划,则可以避免排序。

如果您愿意假设分区编号将按值排序(我不知道这是否确实有保证,但即使在分区拆分后似乎也是如此),则向分区的排序添加前导列数字实现了这一点

SELECT DateRecorded,
       Latitude,
       Longitude
FROM   MachineryReading
WHERE  MachineryId = 2127 
       AND DateRecorded > '2017-01-10' 
       AND DateRecorded < '2017-10-16' 
       AND FixStatus >= 2 
ORDER  BY $PARTITION.pf1(DateRecorded),
          MachineryId, --Not really needed as this is a constant 2127
          DateRecorded 
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明