添加一个额外的“order by”列给了我一个更糟糕的计划

Mar*_*lli 3 performance sql-server optimization order-by sql-server-2016 query-performance

换句话说,我怎样才能摆脱下图中的sort操作符?

在此处输入图片说明

上图显示了以下2个select的执行计划

                SELECT   TOP 1 so.OrgType, 
                              ch.Status, 
                              rcs.DBSstatusDescription, 
                              cid.ApplicationId
                   FROM   tbl_application_crb_initialData cid

                   INNER JOIN  tbl_season_organisationId so
                          ON   cid.OrganisationId = so.OrgId

                   LEFT JOIN  tbl_crbHistory ch  
                          ON  cid.ClientReference = ch.ClientReference

                   LEFT JOIN  ref_crbStatus rcs
                         ON   ch.Status = rcs.statusId    

                   ORDER BY  cid.DateAdded DESC, ch.DateAdded DESC

                SELECT   TOP 1 so.OrgType, 
                              ch.Status, 
                              rcs.DBSstatusDescription, 
                              cid.ApplicationId
                   FROM   tbl_application_crb_initialData cid

                   INNER JOIN  tbl_season_organisationId so
                          ON   cid.OrganisationId = so.OrgId

                   LEFT JOIN  tbl_crbHistory ch  
                          ON  cid.ClientReference = ch.ClientReference

                   LEFT JOIN  ref_crbStatus rcs
                         ON   ch.Status = rcs.statusId    

                   ORDER BY  cid.DateAdded DESC--, ch.DateAdded DESC
Run Code Online (Sandbox Code Playgroud)

唯一的区别是在第二个查询中,order by 中只有一列。

它会有所作为,因为我正在使用top 1

我相信所有需要的信息都在查询计划中可以看到的索引和表定义

如果还有什么可以帮助摆脱这种情况sort,请告诉我,明天我将发布所有可能的信息。

Mar*_*ith 8

您的问题缺少很多细节,但我可以重现类似的内容。

设置

CREATE TABLE T1(X INT PRIMARY KEY, Y INT INDEX IX)

CREATE TABLE T2(X INT, Y INT , PRIMARY KEY(X, Y))

INSERT INTO T2 
OUTPUT INSERTED.* INTO T1
SELECT TOP 1000000 ROW_NUMBER() OVER (ORDER BY @@SPID), ROW_NUMBER() OVER (ORDER BY @@SPID)
FROM sys.all_objects o1, sys.all_objects o2;
Run Code Online (Sandbox Code Playgroud)

查询 1

SELECT TOP 1 T1.Y AS T1Y, T2.Y AS T2Y
FROM T1 JOIN T2 ON T1.X = T2.X 
ORDER BY T1.Y;
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

查询 2

SELECT TOP 1 T1.Y AS T1Y, T2.Y AS T2Y
FROM T1 JOIN T2 ON T1.X = T2.X 
ORDER BY T1.Y, T2.Y
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

查询 3

WITH T  AS
(
SELECT TOP 1 WITH TIES T1.Y AS T1Y, T2.Y AS T2Y
FROM T1 JOIN T2 ON T1.X = T2.X 
ORDER BY T1.Y
)
SELECT TOP 1 *
FROM T 
ORDER BY T2Y
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

查询 1只是TOP 1按照所需的排序顺序从索引中选取,并在该行的另一个表上执行所需的连接。如果连接成功,它会在那里停止,否则它会按索引顺序尝试下一个,直到找到匹配的行或用完行。

查询 2添加新排序列时,此计划不再有效,因为可能有多个匹配项与该TOP 1值相关联,并且 SQL Server 决定加入整个批次,然后从中获取TOP 1

查询 3这鼓励 SQL Server 坚持第一个策略,然后只TOP 1 Sort对与第一个排序键的相同值绑定的任何行执行 a 。

对于我的示例数据,查询 3 的效果比查询 2 更好,但是如果您有许多重复项与第一个排序键的值相关联,那么您的里程数可能会有所不同。

你可以试试这个重写,看看它的票价

WITH T
     AS (SELECT TOP 1 WITH TIES so.OrgType,
                                ch.Status,
                                rcs.DBSstatusDescription,
                                cid.ApplicationId,
                                ch.DateAdded AS chDateAdded
         FROM   tbl_application_crb_initialData cid
                INNER JOIN tbl_season_organisationId so
                        ON cid.OrganisationId = so.OrgId
                LEFT JOIN tbl_crbHistory ch
                       ON cid.ClientReference = ch.ClientReference
                LEFT JOIN ref_crbStatus rcs
                       ON ch.Status = rcs.statusId
         ORDER  BY cid.DateAdded DESC)
SELECT TOP 1 OrgType,
             Status,
             DBSstatusDescription,
             ApplicationId
FROM   T
ORDER  BY chDateAdded DESC 
Run Code Online (Sandbox Code Playgroud)