【问题标题】:Is it possible to improve sort perfomance of ID-based list of rows?是否可以提高基于 ID 的行列表的排序性能?
【发布时间】:2015-07-20 14:16:00
【问题描述】:

考虑以下示例:

SET NOCOUNT ON;
    CREATE TABLE #Users
    (
        ID          INT IDENTITY(1,1),
        Name    VARCHAR(50)
    );
    CREATE CLUSTERED INDEX IDX_C_Users_UserID ON #Users(ID);

  --  CREATE INDEX IDX_Users_Name ON #Users(Name); -- It doesn't work.

    CREATE TABLE #Towns
    (
        ID          INT IDENTITY(1,1),
        Name    VARCHAR(50)
    );
    CREATE CLUSTERED INDEX IDX_C_Towns_UserID ON #Towns(ID)

    CREATE TABLE #BeenHere
    (
        ID INT IDENTITY(1,1), -- for some business reason we can't use clustered index on them
        UserID INT,
        TownID INT
    );

    CREATE UNIQUE INDEX IDX_BEEN_THERE ON #BeenHere(TownID, UserID);


    INSERT INTO #Towns
    SELECT Prefix+Suffix FROM (
        SELECT Prefix, Suffix FROM
        (SELECT 'China' UNION ALL
         SELECT 'Ham' UNION ALL
         SELECT 'Chicken' UNION ALL
         SELECT 'Great' UNION ALL
         SELECT 'Loud'
        ) as A(Prefix)
        CROSS JOIN
        (SELECT 'town' UNION ALL
         SELECT 'water' UNION ALL
         SELECT ' City' UNION ALL
         SELECT 'burg' UNION ALL 
         SELECT 'berg') AS B(Suffix)
    ) Q
    ORDER BY NEWID()
    ;


    INSERT INTO #Users(Name)
    SELECT Name + ' ' + Surname FROM (
        SELECT Name, Surname FROM
        (SELECT 'John' UNION ALL
         SELECT 'Mary' UNION ALL
         SELECT 'Ann' UNION ALL
         SELECT 'Salomon' UNION ALL
         SELECT 'Lisa' UNION ALL
         SELECT 'Patricia' UNION ALL
         SELECT 'David' UNION ALL
         SELECT 'Patrick' UNION ALL
         SELECT 'John' UNION ALL
         SELECT 'Harry' UNION ALL
         SELECT 'Richard' UNION ALL
         SELECT 'George'
         ) as A(Name)
         CROSS JOIN
         (SELECT 'Smith' UNION ALL
         SELECT 'Kowalski' UNION ALL
         SELECT 'Bush' UNION ALL
         SELECT 'Truman' UNION ALL
         SELECT 'Clinton' UNION ALL
         SELECT 'Reagan' UNION ALL
         SELECT 'Lincoln' UNION ALL
         SELECT 'Goldberg' UNION ALL
         SELECT 'Adams' UNION ALL
         SELECT 'Wilson' UNION ALL
         SELECT 'Carter') as B(Surname)

    ) P
    ORDER BY NEWID();


    INSERT INTO #BeenHere(UserID, TownID)
    SELECT 
        TOP 10 PERCENT
        #Users.ID,
        #Towns.ID
        FROM
        #Users
        CROSS JOIN
        #Towns
        ORDER BY NEWID();

SET NOCOUNT OFF;

SELECT 
    Towns.Name,
    (SELECT Users.ID, Users.Name FROM #Users Users INNER JOIN #BeenHere BH ON Users.ID = BH.UserID WHERE BH.TownID = Towns.ID ORDER BY Users.Name FOR XML PATH('User'), ROOT('Users'), TYPE) as BeenThere
    FROM #Towns Towns
    ORDER BY Towns.Name;

DROP TABLE #BeenHere;
DROP TABLE #Users;
DROP TABLE #Towns;

正如我们在执行计划中看到的,对用户进行排序花费了上次查询所消耗资源的 78%。

是否可以在这些表上放置一些索引以提高排序性能?我不能向数据库引入向后不兼容的更改,例如在 #BeenHere(UserID, TownID) 上提供聚集索引。

【问题讨论】:

  • 不,我们在执行计划中看不到任何内容,因为您没有包含它。
  • 提醒一下,计划中的百分比只是估计值
  • 在第一次创建索引时,您已经用 ; 关闭了它。为什么甚至在#BeenHere 中有 ID INT IDENTITY。为什么要在插入时使用 newID 排序来分割索引?
  • " 为什么在#BeenHere 中甚至有 ID INT IDENTITY" -> 因为我正在处理的旧数据库使用这种毫无意义的约定。 “为什么要在插入时使用 newID 排序来分割索引”-> 因为它更好地模拟了我必须处理的真实数据。
  • 使用 CI 可以做的任何事情都可以用 NCI 做。只需包括所有必需的列。然后你得到几乎相同的物理数据结构。s

标签: sql-server tsql sqlperformance sql-optimization


【解决方案1】:

我只是将您的聚集索引替换为这个:

CREATE CLUSTERED INDEX IDX_C_Users_Name_UserID ON #Users(Name, ID);

所以现在您的表格按Name 排序,而不是按ID

SORT 运算符已从执行计划中消失。

更新
正如您所说,您无法更改聚集索引。如果你愿意,有一种方法可以做到这一点。您的 NONCLUSTERED INDEX 在 Name only 列上很好,但 SQL Server 决定不使用它。你可以做的是在你的表中添加一个提示来使用这个索引:

SELECT Towns.Name
    , (
        SELECT Users.ID, Users.Name
        FROM #Users Users WITH (INDEX (IDX_Users_Name))
        INNER JOIN #BeenHere BH
            ON Users.ID = BH.UserID
        WHERE BH.TownID = Towns.ID
        ORDER BY Users.Name
        FOR XML PATH('User'), ROOT('Users'), TYPE
        ) AS BeenThere
FROM #Towns Towns
ORDER BY Towns.Name;

然后您的查询将使用此索引,并且排序运算符将不再存在。但是,我不确定这是否是最有效的方法。然后 SQL Server 必须扫描索引,而不是寻找它。

【讨论】:

  • 我没有使用外键来简化测试用例。无论如何 - 我不能做出这样的改变,因为它需要修改数百个表和数百个 SP。
【解决方案2】:

您的问题是相关子查询的使用。停止使用这些并改用联接(如果必须,包括派生表)。相关子查询逐行运行,而不是针对整个集合,因此是性能猪。一个。

【讨论】:

  • 它将削弱需要 XML 字段(遗留代码库)的客户端。
猜你喜欢
  • 2019-12-29
  • 2011-10-30
  • 1970-01-01
  • 1970-01-01
  • 2017-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多