【问题标题】:RANK() SQL Server execution plan issueRANK() SQL Server 执行计划问题
【发布时间】:2017-11-22 01:07:18
【问题描述】:

是什么促使 SQL Server 对返回超过 6000 行的查询使用不太理想的执行计划?对于返回所有行的情况,我需要提高查询性能。

我选择所有字段并在索引中包含的相同三列上添加排名。根据返回的行数,查询有两种不同的执行计划,因此执行时间分别为 0.2s 或 3s。

从 1 行返回到 ca。 5000 个查询运行速度很快。从 6000 行到全部返回,查询运行缓慢。

Table1 大约有。 38000 行。数据库在 Azure SQL v12 上运行。

表:

CREATE TABLE [dbo].[Table1](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [KOD_ID] [int] NULL,
    [SYM] [nvarchar](20) NULL,
    [AN] [nvarchar](35) NULL,
    [A] [nvarchar](10) NULL,
    [B] [nvarchar](2) NULL,
    [C] [datetime] NULL,
    [D] [datetime] NULL,
 CONSTRAINT [PK_Table1] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
GO

CREATE NONCLUSTERED INDEX [IX_Table1] ON [dbo].[Table1]
(
    [KOD_ID] ASC,
    [SYM] ASC,
    [AN] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO

查询:

SELECT TOP 6000 *, RANK() OVER(ORDER BY KOD_ID ASC, SYM ASC, AN ASC) AS Rank#
FROM [dbo].[Table1]

SELECT TOP 7000 *, RANK() OVER(ORDER BY KOD_ID ASC, SYM ASC, AN ASC) AS Rank#
FROM [dbo].[Table1]

两个查询的执行计划

【问题讨论】:

  • * 有必要吗?这禁止使用覆盖索引,将优化器推入一个简单地扫描聚集索引并首先对整个表进行排序的计划,因为它认为非聚集索引不会充分减少 I/O(显然,事实证明,排序需要更多时间)。尝试将ORDER BY KOD_ID ASC, SYM ASC, AN ASC 作为一个整体添加到查询中,这可能会使平衡再次有利于索引。
  • @JeroenMostert 绝对没有必要。我已将 * 替换为明确的列名,但这没有帮助。
  • 这不是我的意思,我的意思是您是否真的需要 all 列。 * 与拼写出来没有区别(性能方面)。
  • 理论上,可以通过加入子查询来强制进行书签查找:SELECT TOP(7000) T.*, T1.Rank# FROM (SELECT TOP(7000) ID, RANK() OVER(ORDER BY KOD_ID ASC, SYM ASC, AN ASC) AS Rank# FROM Table1 ORDER BY ID) T JOIN Table1 ON T.ID = Table1.ID。但是,即使它有效,这也是相当棘手的,因为它会阻止优化器执行单个表扫描,即使这确实是最好的方法。重新排列您的表(如答案中所示)是另一种有前途的方法。
  • @JeroenMostert TOP 子句仅用于发现和演示性能变化。现实生活中的要求是返回所有行,所以加入工作完美。这就是我最终做到的方式。我将剩余的列与 ID 列上的排名子查询 SELECT ID, RANK() OVER(ORDER BY KOD_ID ASC, SYM ASC, AN ASC) AS Rank# FROM [dbo].[Table1] 连接起来。

标签: sql sql-server performance sql-execution-plan


【解决方案1】:
CREATE NONCLUSTERED INDEX [IX_Table1] ON [dbo].[Table1]
(
    [KOD_ID] ASC,
    [SYM] ASC,
    [AN] ASC
) INCLUDE ([A], [B], [C], [D]);

创建这种覆盖索引,它应该扫描这个索引并且很可能甚至不需要排序,因为它的数据已经在索引中排序。

您查询的要点是:

  1. 第一个计划有一个键查找,尽可能避免它们(键查找是对每一行的额外扫描,因为索引没有它们)创建包含列的覆盖索引
  2. 也避免排序操作,它们对 SQL Server 来说代价高昂

如果您对索引重建感到满意并且喜欢读取而不是插入,考虑到这一点,这些可能是您的表的替代 DDL,KOD_IDSYMAN 不能为空:

如果需要ID来保证唯一性:

CREATE TABLE [dbo].[Table1] (
    [KOD_ID] [int] NOT NULL
    , [SYM] [nvarchar](20) NOT NULL
    , [AN] [nvarchar](35) NOT NULL
    , [ID] [int] IDENTITY(1, 1) NOT NULL
    , [A] [nvarchar](10) NULL
    , [B] [nvarchar](2) NULL
    , [C] [datetime2] NULL
    , [D] [datetime2] NULL
    , CONSTRAINT [PK_Table1] PRIMARY KEY CLUSTERED ([KOD_ID], [SYM], [AN], [ID])
    );
GO

如果不需要ID 来确保唯一性:

CREATE TABLE [dbo].[Table1] (
    [KOD_ID] [int] NOT NULL
    , [SYM] [nvarchar](20) NOT NULL
    , [AN] [nvarchar](35) NOT NULL
    , [A] [nvarchar](10) NULL
    , [B] [nvarchar](2) NULL
    , [C] [datetime2] NULL
    , [D] [datetime2] NULL
    , CONSTRAINT [PK_Table1] PRIMARY KEY CLUSTERED ([KOD_ID], [SYM], [AN])
    );
GO

另外,请注意我使用datetime2 而不是datetime,这是微软推荐的:https://docs.microsoft.com/en-us/sql/t-sql/data-types/datetime-transact-sql

使用 timedatedatetime2datetimeoffset 数据 新作品的类型。这些类型符合 SQL 标准。他们是 更便携。 timedatetime2datetimeoffset 提供 更多秒精度。 datetimeoffset 提供时区支持 用于全球部署的应用程序。

【讨论】:

  • 虽然这肯定会覆盖查询,但它实际上复制了整个表。这意味着所有插入和更新都变得更加昂贵,因此必须注意不要过度影响这种性能。
  • 对,所以你应该把它设为聚集索引。
  • @DavidBrowne-Microsoft:这也不一定是真的,因为目前,clindex 是IDENTITY。这对于序列化插入很有用;在插入时不按顺序排列的列上创建聚集索引会导致严重的索引碎片,也会损害所有其他查询。 (但这当然值得考虑,而不是将所有数据存储两次。)
  • 好吧,最终这取决于 OP 需要什么,这些是插入还是读取。如果这些 ID 没有意义,并且我永远不会通过该主键运行查询 - 我最好创建一个聚集索引,这将有利于我的读取查询。
  • 第二种选择几乎肯定没有意义,因为如果KOD_IDSYMAN 是唯一的,则RANK() 没有联系,可以使用更简单的ROW_NUMBER()。请注意,主键不必是聚集索引,聚集索引也不必是唯一的;你可以有ID INT IDENTITY PRIMARY KEY NONCLUSTEREDCREATE CLUSTERED INDEX ... (KOD_ID, SYM, AN)。生成的索引会更小,以便启动(尽管只有完全丢弃主键才能减少总空间)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-30
  • 2011-04-12
  • 2021-12-09
相关资源
最近更新 更多