为什么 SQL Server 选择聚集索引扫描而不是非聚集索引扫描?

2023-12-22

在我正在查询的一个表中,聚集索引是在非主键的键上创建的。 (我不知道为什么。)

但是,该表的主键有一个非聚集索引。

在执行计划中,SQL 选择聚集索引,而不是我在查询中使用的主键的非聚集索引。

SQL 这样做有什么原因吗?如何强制 SQL 选择非聚集索引?


追加更多细节:

表有很多字段,查询包含很多联接。让我抽象一下。

表定义如下所示:

SlowTable
[SlowTable_id] [int] IDENTITY(200000000,1) NOT NULL,
[fk1Field] [int] NULL,
[fk2Field] [int] NULL,
[other1Field] [varchar] NULL,
etc. etc...

然后该表的索引是:

fk1Field (Clustered)
SlowTable_id (Non-Unique, Non-Clustered)
fk2Field (Non-Unique, Non-Clustered)
... and 14 other Non-Unique, Non-Clustered indices on other fields

据推测,针对 fk1Field 进行了更多查询,这就是为什么他们选择它作为聚集索引的基础。

我的查询使用视图:

SELECT
  [field list]
FROM 
     SourceTable1 S1
     INNER JOIN SourceTable2 S2
       ON S2.S2_id = S1.S2_id
     INNER JOIN SourceTable3 S3
       ON S3.S3_id = S2.S3_id
     INNER JOIN SlowTable ST
       ON ST.SlowTable_id = S1.SlowTable_id
     INNER JOIN [many other tables, around 7 more...]

执行计划比较大,涉及的节点说

Hash Match 
(Inner Join)
Cost: 9%

有一个粗箭头指向

Clustered Index Scan (Clustered)
SlowTable.fk1Field 
Cost: 77%

我希望这能提供有关该问题的足够详细信息。

Thanks!


附录 2: 对我之前帖子的更正。该视图没有 where 子句。它只是一系列内部联接。执行计划取自在复杂查询中使用视图(列为 SLOW_VIEW)的 Insert 语句,如下所示:

(此存储过程的作用是根据权重对某些记录的总量进行按比例分割,权重计算为占总数的百分比。这模仿了将一个值从一个帐户分配到其他帐户的情况。)

INSERT INTO dbo.WDTD(
    FieldA,
    FieldB,
    GWB_id,
    C_id,
    FieldC,
    PG_id,
    FieldD,
    FieldE,
    O_id,
    FieldF,
    FieldG,
    FieldH,
    FieldI,
    GWBIH_id,
    T_id,
    JO_id,
    PC_id,
    PP_id,
    FieldJ,
    FieldK,
    FieldL,
    FieldM,
    FieldN,
    FieldO,
    FieldP,
    FieldQ,
    FieldS)
SELECT DISTINCT
    @FieldA FieldA,
    GETDATE() FieldB,
    @Parameter1 GWB_id,
    GWBIH.C_id C_id,
    P.FieldT FieldC,
    P.PG_id PG_id,
    PAM.FieldD FieldD,
    PP.FieldU FieldE,
    GWBIH.O_id O_id,
    CO.FieldF FieldF,
    CO.FieldG FieldG,
    PSAM.FieldH FieldH,
    PSAM.FieldI FieldI,
    SOURCE.GWBIH_id GWBIH_id,
    ' ' T_id,
    GWBIH.JO_id JO_id,
    SOURCE.PC_id PC_id,
    GWB.PP_id,
    SOURCE.FieldJ FieldJ,
    1 FieldK,
    ROUND((SUM(GWBIH.Total) / AGG.Total) * SOURCE.Total, 2) FieldL,
    ROUND((SUM(GWBIH.Total) / AGG.Total) * SOURCE.Total, 2) FieldM,
    0 FieldN,
    ' ' FieldO,
    ESGM.FieldP_flag FieldP,
    SOURCE.FieldQ FieldQ,
     '[UNPROCESSED]'
FROM
    dbo.Table1 GWBIH
    INNER JOIN dbo.Table2 GWBPH
        ON GWBPH.GWBP_id = GWBIH.GWBP_id
    INNER JOIN dbo.Table3 GWB
        ON GWB.GWB_id = GWBPH.GWB_id
    INNER JOIN dbo.Table4 P
        ON P.P_id = GWBPH.P_id
    INNER JOIN dbo.Table5 ESGM
        ON ESGM.ET_id = P.ET_id
    INNER JOIN dbo.Table6 PAM
        ON PAM.PG_id = P.PG_id
    INNER JOIN dbo.Table7 O
        ON O.dboffcode = GWBIH.O_id
    INNER JOIN dbo.Table8 CO
        ON
            CO.Country_id = O.Country_id
            AND CO.Brand_id = O.Brand_id
    INNER JOIN dbo.Table9 PSAM
        ON PSAM.Office_id = GWBIH.O_id
    INNER JOIN dbo.Table10 PCM
        ON PCM.PC_id = GWBIH.PC_id
    INNER JOIN dbo.Table11 PC
        ON PC.PC_id = GWBIH.PC_id
    INNER JOIN dbo.Table12 PP
        ON PP.PP_id = GWB.PP_id
            -- THIS IS THE VIEW THAT CONTAINS THE CLUSTERED INDEX SCAN
    INNER JOIN dbo.SLOW_VIEW GL
        ON GL.JO_id = GWBIH.JO_id
    INNER JOIN (
        SELECT
            GWBIH.C_id C_id,
            GWBPH.GWB_id,
            SUM(GWBIH.Total) Total
        FROM
            dbo.Table1 GWBIH
            INNER JOIN dbo.Table2 GWBPH
                ON GWBPH.GWBP_id = GWBIH.GWBP_id
            INNER JOIN dbo.Table10 PCM
                ON PCM.PC_id = GWBIH.PC_id
        WHERE
            PCM.Split_flag = 0
            AND GWBIH.JO_id IS NOT NULL
        GROUP BY
            GWBIH.C_id,
            GWBPH.GWB_id
            ) AGG
        ON AGG.C_id = GWBIH.C_id
            AND AGG.GWB_id = GWBPH.GWB_id
    INNER JOIN (
        SELECT
            GWBIH.GWBIH_id GWBIH_id,
            GWBIH.C_id C_id,
            GWBIH.FieldQ FieldQ,
            GWBP.GWB_id GWB_id,
            PCM.PC_id PC_id,
            CASE
            WHEN WT.FieldS IS NOT NULL
                THEN WT.FieldS
            WHEN WT.FieldS IS NULL
                THEN PCMS.FieldT
            END FieldJ,
            SUM(GWBIH.Total) Total
        FROM
            dbo.Table1 GWBIH
            INNER JOIN dbo.Table2 GWBP
                ON GWBP.GWBP_id = GWBIH.GWBP_id
            INNER JOIN dbo.Table4 P
                ON P.P_id = GWBP.P_id
            INNER JOIN dbo.Table10 PCM
                ON PCM.PC_id = GWBIH.PC_id
            INNER JOIN dbo.Table11 PCMS
                ON PCMS.PC_id = PCM.PC_id
            LEFT JOIN dbo.WT WT
                ON WT.ET_id = P.ET_id
                AND WT.PC_id = GWBIH.PC_id
        WHERE
            PCM.Split_flag = 1
        GROUP BY
            GWBIH.GWBI_id,
            GWBIH.C_id,
            GWBIH.FieldQ,
            GWBP.GWB_id,
            WT.FieldS,
            PCM.PC_id,
            PCMS.ImportCode
            ) SOURCE
        ON SOURCE.C_id = GWBIH.C_id
            AND SOURCE.GWB_id = GWBPH.GWB_id
WHERE
    PCM.Split_flag = 0
    AND AGG.Total > 0
    AND GWBPH.GWB_id = @Parameter1
    AND NOT EXISTS (
        SELECT *
        FROM dbo.WDTD
        WHERE
            TD.C_id = GWBIH.C_id
            AND TD.FieldA = GWBPH.GWB_id
            AND TD.JO_id = GWBIH.JO_id
            AND TD.PC_id = SOURCE.PC_id
            AND TD.GWBIH_id = ' ')
GROUP BY
    GWBIH.C_id,
    P.FieldT,
    GWBIH.JO_id,
    GWBIH.O_id,
    GWBPH.GWB_id,
    P.PG_id,
    PAM.FieldD,
    PP.FieldU,
    GWBIH.O_id,
    CO.FieldF,
    CO.FieldG,
    PSAM.FieldH,
    PSAM.FieldI,
    GWBIH.JO_id,
    SOURCE.PC_id,
    GWB.PP_id,
    SOURCE.FieldJ,
    ESGM.FieldP_flag,
    SOURCE.GWBIH_id,
    SOURCE.FieldQ,
    AGG.Total,
    SOURCE.Total

附录 3:在视图的 select 语句上执行执行计划时,我看到以下内容:

Hash Match     <====   Bitmap           <------ etc...
(Inner Join)           (Bitmap Create)
Cost: 0%               Cost: 0%
    ^
    |
    |
Parallelism                           Clustered Index Scan (Clustered)
(Repartition Streams)    <====        Slow_Table.fk1Field
Cost: 1%                              Cost: 98%

附录 4:我想我发现了问题。聚集索引扫描并不是指我引用主键的子句,而是指另一个需要一个在某种程度上与上面的 fk1Field 相关的字段的子句。


最有可能的是以下之一:

  • 行数过多使索引无效
  • 索引不符合 ON/WHERE 条件
  • 索引未覆盖,SQL Server 避免了键查找

更新后编辑:

你的索引没有用,因为它们都是单列索引,所以它会进行聚集索引扫描。

您需要一个与 ON、WHERE、GROUP BY 条件以及 SELECT 列表的 INCLUDES 相匹配的索引。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 SQL Server 选择聚集索引扫描而不是非聚集索引扫描? 的相关文章

  • SQL 查询 - 将查询中的日期格式更改为 DD/MM/YYYY

    我想要实现的目标相当简单 将一种日期格式转换为另一种日期格式 由此 Jan 30 2013 12 00 00 000AM对此 DD MM YYYY或者在这种情况下30 01 2013 但是 当它是该月的 1 号到 9 号时 日期格式缺少零并
  • 确定自上次访问 SQL Server 以来的行更改

    我们有一个多用户系统 用户将数据保存到中央 SQL Server 2005 数据库中 我们遇到了一个问题 即一个用户刷新数据库中的更改 而另一个用户保存新数据 我们当前收集更改的方式是每个表上都有一个时间戳列 该列在每行插入 更新时都会填充
  • ASP.NET Core 7.0 登录时出错:证书链由不受信任的机构颁发

    我使用 SQL Server 创建了一个简单的 NET 7 0 应用程序 如果我使用默认的 localdb 甚至在将其更改为 网络服务器 之后 我会收到以下错误 证书链是由不受信任的机构颁发的 我的连接字符串是 mysqlserver co
  • INSERT INTO ... SELECT ... 是否始终按序号位置匹配字段?

    我的测试似乎证实了这一点 INSERT INTO a x y SELECT y x FROM b maps b y to a x 即字段仅按顺序位置匹配 而不按名称匹配 情况总是如此吗 即 我可以依赖这种行为吗 很遗憾 文档 http ms
  • 参数的性能不如硬编码值

    我有一个执行得很糟糕的存储过程 当我声明一个变量时 设置它的值 然后在 where 子句中使用它 该语句需要一个多小时才能运行 当我对 where 子句中的变量进行硬编码时 它的运行时间不到一秒 我开始通过执行计划来查找问题所在 看起来当我
  • 如何为不存在的值创建一行并用 0 值填充计数?

    在 SQL Server 中 我对数据上的用户年龄组运行查询 其中 在某些年里 每个年龄组的用户数为零 例如 2013 年有 18 21 年龄组的用户 因此查询返回下一个年龄组 22 25 作为第一行 因为没有包含 18 21 的条目 相反
  • SQL Server:读取数据库图表的权限

    您能否告知 授予用户读取 SQL Server 2005 中数据库图表的权限需要什么权限 多谢 From BOL http msdn microsoft com en us library ms186345 28SQL 90 29 aspx
  • 为什么 Sql Server 2000 上的 TSQL 对小数点的舍入不一致?

    我正在尝试计算美元金额的折扣百分比 在 50 的情况下 有时你会得到半分钱 我需要将其四舍五入到最接近的一分钱 在Sql中 我的计算如下 round retail 0 5 2 0 如果我采用以下值 我会得到不同的结果 4 39 2 49 不
  • Pandas read_sql 读取时更改大量 ID

    我将 Oracle 数据库转移到 SQL Server 一切似乎都很顺利 各种 ID 列都是很大的数字 因此我不得不使用 Decimal 因为它们对于 BigInt 来说太大了 我现在尝试使用 pandas read sql 使用 pyod
  • 帮助将二进制图像数据从 SQL Server 读取到 PHP 中

    我似乎无法找到将二进制数据从 SQL 服务器读取到 PHP 的方法 我正在开发一个项目 需要能够将图像直接存储在 SQL 表中 而不是文件系统上 目前 我一直在使用这样的查询 插入 myTable 文档 选择 从 OPENROWSET BU
  • 默认情况下 dbo 架构中的 EF 6 Code First __MigrationHistory

    我是代码优先实体框架的新手 第一次运行我的应用程序后登录数据库时 当我看到 MigrationHistory 表时 我有点困惑 我现在了解对此表的需求 但不喜欢它位于用户表内的标准 dbo 模式中 我认为它很唐突且有风险 我的第一个想法是将
  • 查找 SQL Server 中表的 B 树高度

    由于数据库数据以B Tree的形式组织在8k页中 对于PK信息也是如此 数据库中的每个表都应该可以计算B Tree的高度 从而揭示达到某些数据需要多少次跳跃 由于行大小和 PK 大小都非常重要 因此很难计算 因为例如varchar 250
  • LINQ to SQL:从位于不同服务器上的两个数据库获取记录

    我需要从两个不同的表中获取记录 数据库位于两个不同的 SQL Server 中 例如 销售数据库位于服务器 1 上 采购数据库位于服务器 2 上 销售和采购数据库都有一些表集 例如销售数据库中的 table1 和采购数据库中的 table2
  • T-SQL 中结果集的幂集(所有组合)

    我需要一个 t sql 代码来获取结果集的幂集 输入示例 ColumnName 1 2 3 Example Output one columns as nvarchar 1 2 3 1 2 1 3 2 3 1 2 3 输出集可能包含重复值
  • 在 WHERE 子句中使用可选参数

    我有一个SP ALTER PROCEDURE dbo sp Compare lst varchar 100 frst varchar 100 NULL passportNo varchar 50 NULL AS SELECT FROM db
  • 随机排列每行的列值

    我正在使用 C NET 开发多项选择题考试生成器 每次做出报告时 都会在数据库中随机挑选问题 并随机调整选项 我可以做随机问题部分 但我不能做选择的洗牌 我有一张表 其中一行如下 question answer distractor1 di
  • 如何创建实体集或模型而不在数据库中创建相应的表 - 实体框架

    我的 sqlserver 数据库中有一个存储过程 它返回多个结果集 我正在使用 msdn 中的以下链接从实体框架中的 SP 读取多个结果集 https msdn microsoft com en us library jj691402 v
  • 为什么 SSRS 报表从 SQL Server Reporting Services 运行时生成的数据与使用“预览”选项卡运行时生成的数据不同?

    我有一个运行我想要的数据的报表 从 预览 选项卡 即 或者在 VS 2010 中使用 F5 运行时 但是当我将报表 rdl 文件 上传到 SQL Server Reporting Services 并运行更新后的报表时从那里报告 它仍然显示
  • Sql批量复制截断小数

    当我使用批量复制将十进制值从 C DataTable 插入 Sql Server 2005 时 值会被截断而不是四舍五入 DataTable 中的数据类型为 Decimal 数据库中的数据类型为Decimal 19 3 数据表中的值为 1
  • 如何在SQL Compact Edition中导入数据? [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我似乎没有找到合适的工具 也没有找到

随机推荐

  • toString 的显式调用与隐式调用

    当需要有关对象的一些调试信息时 我曾经使用 toString 的隐式调用 因为如果对象为 null 它不会抛出异常 例如 System out println obj obj 代替 System out println obj obj to
  • 在 Linux 上安装 RPostgreSQL

    当我在 R 中尝试 Linux 时 install packages RPostgreSQL 它因未指定的错误而失败 Warning message In install packages RPostgreSQL installation
  • DataGridView“索引-1没有值”

    我在 VS 2013 中创建的 WindowsForms 应用程序中的 DataGridView 出现问题 应用程序在调试构建中没有异常 但是当我切换到发布构建并尝试单击 datagridview 单元格时 出现异常 异常 抛出 索引 1
  • 将列顺序从移动布局更改为桌面布局

    我正在尝试使用网格布局实现以下设计 这是我尝试过的 但不是我想要的 http jsfiddle net tomalex0 3fesK 3 http jsfiddle net tomalex0 3fesK 3 div div class co
  • spring 和 angular2 如何使用参数请求发布数据?

    angular2如何使用参数请求数据 以及spring requestParam or requestBody像这样 后台账户登录 param userName userName param password password return
  • AspNetCore.Identity 不适用于自定义用户/角色实现

    因为我倾向于偏爱Guid作为我的主键类型 我的User and Role类的实现如下 public class User IdentityUser
  • PHP-在下拉菜单中递归列出所有目录和子目录[重复]

    这个问题在这里已经有答案了 可能的重复 PHP 获取给定目录的所有子目录 https stackoverflow com questions 2524151 php get all subdirectories of a given dir
  • 如何使用 range 函数在字符串中插入空格?

    例如 如果我有一个字符串 其内容为 你好 你今天好吗 乔 我如何能够定期在其中插入空格 例如 我想在以下步骤中使用 range 函数向其中插入空格 range 0 27 2 所以它看起来像这样 He ll o ho w ar e yo u
  • 使用 jwplayer 进行动态 rtmp 流传输

    我正在尝试使用 javascript 和 php 发布动态 RTMP 流 我想从 url 获取流名称并在我的网络播放器 jwplayer 上发布流 喜欢xxx com watch php chanel music 我想使用音乐作为我的流名称
  • Gitkraken 桌面应用程序 - 登录错误:“请登录以继续”

    谁一直使用GitKraken作为GIT客户端 你会知道需要身份验证吗 对于应用程序 请使用以下方式登录 电子邮件受保护 cdn cgi l email protection 存储库包含 电子邮件受保护 cdn cgi l email pro
  • 使用按位运算符将 byte 转换为 int

    我正在用 Java 记录一些代码 目标是阅读并处理OSRM文件 http project osrm org 这是一个包含十六进制代码的文件 流程如下 读入某个字节到aByteBuffer用一个FileChannel 缓冲区填满后 将每个字节
  • 带有匿名方法的BackgroundWorker?

    我要创建一个后台工作者使用匿名方法 我写了以下代码 BackgroundWorker bgw new BackgroundWorker bgw DoWork new DoWorkEventHandler gt int i 0 foreach
  • Matlab函数计算平均邻度

    我尝试搜索 matlab 的函数 该函数给出平均邻度的图表 python 中的 network X 包中有一个相同的函数 所以我想知道matlab中是否有类似的功能 编辑 我无法将其转换为邻接矩阵 这实际上会占用太多空间 我所拥有的是以下边
  • C++ 将源文件中的某些函数设为私有的最佳方法是什么?

    myclass h pragma once void publicFunction myclass cpp include myclass h include
  • Android:如何以编程方式取消 SearchView 的焦点

    我的布局中有一个 SearchView 不在操作栏中 我无法使用通常的方法关闭键盘 public static void hideKeyboard Activity activity InputMethodManager imm Input
  • Firebase 3.x - 令牌/会话过期

    有谁知道令牌需要多长时间才会过期 现在没有选项可以在控制台上设置令牌有效性 自 2016 年 5 月起 Firebase 身份验证登录会话不再过期 相反 他们使用长期帐户令牌和短期自动刷新访问 ID 令牌的组合来获得两全其美的效果 如果你想
  • Spring Boot程序找不到主类

    我有一个程序在 eclipse 中作为 Spring boot 应用程序运行 程序运行良好 然后我做了以下事情 右键单击项目 gt 运行方式 gt Maven 测试 这是偶然的 当我尝试再次将程序作为 Spring Boot 应用程序运行时
  • 解压 1 个变量,剩余到列表中

    我想知道这是否可能 def someFunction return list range 5 first rest someFunction print first 0 print rest 1 2 3 4 我知道可以用这三行来完成 res
  • SQLAlchemy 查询包含多个值中任意一个的数组

    我想我可以在互联网上的某个地方找到这个问题的答案 但我似乎错过了 您可以查询表中数组列包含特定值的所有行 MyModel query filter Mymodel arrayField contains someValue 您可以输入多个值
  • 为什么 SQL Server 选择聚集索引扫描而不是非聚集索引扫描?

    在我正在查询的一个表中 聚集索引是在非主键的键上创建的 我不知道为什么 但是 该表的主键有一个非聚集索引 在执行计划中 SQL 选择聚集索引 而不是我在查询中使用的主键的非聚集索引 SQL 这样做有什么原因吗 如何强制 SQL 选择非聚集索