AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 328313
Accepted
Greg
Greg
Asked: 2023-06-15 07:43:01 +0800 CST2023-06-15 07:43:01 +0800 CST 2023-06-15 07:43:01 +0800 CST

Sql Perf - 为什么查询执行聚簇索引扫描而不是使用定义的非聚簇索引

  • 772

我有一个对非常大的表执行聚簇索引扫描的查询,该扫描在某些情况下会导致超时。需要帮助理解为什么它不使用定义的非聚集索引。

这是查询:

DECLARE @StartDate datetime = '2023-03-16 00:00:00';

DECLARE @TerminalIds [dbo].[udtBigInt]; -- user defined table with a BIGINT col
INSERT INTO @TerminalIds ([Id])
SELECT [EquipmentId]
FROM #mechanicsTerminal;

SELECT [DataRecId]
    , [RawData]
    , [RecordingTime]
    , [EquipmentId]
FROM [dbo].[Data]
WHERE [EquipmentId] IN (SELECT [Id] FROM @TerminalIds)
AND [RecordingTime] >= @StartDate
ORDER BY [DataRecId] DESC
OFFSET 0 ROWS FETCH NEXT 50 ROWS ONLY;

这是表定义:

CREATE TABLE [dbo].[Data](
    [DataRecId] [bigint] IDENTITY(1,1) NOT NULL,
    [RawData] [nvarchar](max) NOT NULL,
    [CreatedDateUTC] [datetime] NOT NULL,
    [RecordingTime] [datetime] NOT NULL,
    [EquipmentId] [bigint] NOT NULL,
    [DataSetId] [uniqueidentifier] NULL,
    [SourceType] [nvarchar](50) NULL,
    [Name] [nvarchar](100) NULL,
PRIMARY KEY CLUSTERED ( DataRecId] ASC)
GO
ALTER TABLE [EJ].[Data]  WITH CHECK ADD  CONSTRAINT [chk_Data_RawData] CHECK  ((isjson([RawData])=(1)))
GO

以下是索引:

CREATE INDEX [nc_Data_DataSetId_includes] 
ON [dbo].[Data] ( [DataSetId] ) INCLUDE ( [DataRecId], [RawData], [RecordingTime]);
GO
CREATE INDEX [nc_Data_EquipmentId_includes] 
ON [dbo].[Data] ( [EquipmentId] ) INCLUDE ( [DataSetId], [RawData]);
GO
CREATE INDEX [nc_Data_EquipmentId_RecordingTime_Name_includes] 
ON [dbo].[Data] ( [EquipmentId], [RecordingTime], [Name] ) INCLUDE ( [DataRecId], [RawData]);
GO

这是实际的执行计划:

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

使用此特定数据,查询将在亚秒级执行。

然而,有一种情况是 中只有三个记录@TerminalIds,而 中没有匹配的记录[dbo].[Data],查询永远不会完成。这是 45 秒后的计划。

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

我试过的:

  • 更新统计数据并重新编译主过程
  • 继续而不是用子句做子INNER JOIN查询@TerminalIdsIN
query-performance
  • 1 1 个回答
  • 32 Views

1 个回答

  • Voted
  1. Best Answer
    Charlieface
    2023-06-15T09:37:09+08:002023-06-15T09:37:09+08:00

    问题是您在 上使用了不等式RecordingTime,但使用了OFFSET FETCHordered by DataRecId。服务器似乎认为这种排序更重要,会更快地减少行数,所以它求助于扫描主键索引,希望它能快速找到这 50 行。

    您可以nc_Data_EquipmentId_RecordingTime_Name_includes通过像这样重写查询来强制它读取索引

    SELECT DataRecId
        , RawData
        , RecordingTime
        , EquipmentId
    FROM (
        SELECT TOP (1000000000) *
        FROM dbo.Data
        WHERE EquipmentId IN (SELECT Id FROM @TerminalIds)
          AND RecordingTime >= @StartDate
        ORDER BY
          EquipmentId,
          RecordingTime
    ) t
    ORDER BY DataRecId DESC
    OFFSET 0 ROWS FETCH NEXT 50 ROWS ONLY;
    

    假设,正如我所怀疑的那样,您正在使用实体框架之类的 ORM,您可能想要这样的东西

    context.Data
      .Where(d => TerminalIds.Contains(d.EquipmentId) && d.RecordingTime >= StartDate)
      .OrderBy(d => d.EquipmentId)
      .ThenBy(d => d.RecordingTime)
      .Take(1000000000)
      .OrderByDescending(d => d.DataRecId)
      .Take(50)
    

    DataRecId如果您可以首先删除排序依据的要求,那么您可能会显着提高选择正确索引的机会。


    您还应该向表类型添加一个主键。这将从计划中删除排序和假脱机。

    DROP TYPE dbo.udtBigInt;
    CREATE TYPE dbo.udtBigInt (Id bigint PRIMARY KEY);
    
    • 1

相关问题

  • SQL从一个表中获取另一个表中的多个条目的ID

  • 带限制器的键/值表

  • 选择满足 n 个外键条件的行

  • 这种类型的查询的名称是什么,一个有效的例子是什么?

  • TOP 如何(以及为什么)影响执行计划?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve