RANK()SQL Server执行计划问题

时间:2017-06-19 17:51:58

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

是什么驱使SQL Server对返回6000多行的查询使用不太优化的执行计划?我需要提高返回所有行的方案的查询性能。

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

从1行返回到ca. 5000查询运行速度很快。从6000行返回到所有,查询运行缓慢。

var inputElementRect = document.getElementById('YOURINPUTID').getBoundingClientRect() var width = inputElementRect.left - caretRect.left 有约。 38000行。数据库在Azure SQL v12上运行。

表:

Table1

查询:

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

两个查询的执行计划

Execution plans

1 个答案:

答案 0 :(得分:2)

CREATE NONCLUSTERED INDEX [IX_Table1] ON [dbo].[Table1]
(
    [KOD_ID] ASC,
    [SYM] ASC,
    [AN] ASC
) INCLUDE ([A], [B], [C], [D]);

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

您的查询中的关键点是:

  1. 第一个计划有一个密钥查找,尽可能地避免它们(密钥查找是每行的额外扫描,因为索引没有它们)使用INCLUDED列创建覆盖索引
  2. 避免排序操作,它们对SQL Server来说代价高昂。
  3. 如果您正好进行索引重建并支持读取插入,那么这些可能是您的表的备用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,这是Microsoft建议的:https://docs.microsoft.com/en-us/sql/t-sql/data-types/datetime-transact-sql

      

    使用时间日期 datetime2 datetimeoffset 数据   新工作的类型。这些类型与SQL标准一致。他们是   更便携。 时间 datetime2 datetimeoffset 提供   更精确的秒数。 datetimeoffset 提供时区支持   用于全球部署的应用程序。

相关问题