You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何SQL Server建议将谓词列CompanyId放入索引INCLUDE而非键列?

问题:SQL Server为何建议将JOIN条件的CompanyId放入INCLUDE而非键列?

我正在优化一个大型查询并创建索引,原以为自己的索引设计正确,但SQL Server给出了不同建议。相关查询片段如下:

SELECT  CompanyTransaction.Amount
        -- columns from other tables..
FROM Company
    -- JOIN other tables
LEFT JOIN CompanyTransaction
    ON CompanyTransaction.CompanyId = Company.Id
    AND CompanyTransaction.Type = 'SR'
    AND CompanyTransaction.Code = 1000

我根据过滤条件,将CompanyId、Type、Code设为键列,同时把查询需要的Amount放入INCLUDE,创建的索引如下:

CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [dbo].[CompanyTransaction] ([CompanyId],[Type],[Code])
INCLUDE ([Amount])

但SQL Server建议的索引为:

CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [dbo].[CompanyTransaction] ([Type],[Code])
INCLUDE ([CompanyId], [Amount])

这种情况之前也出现过,想了解为何SQL Server认为作为搜索条件的CompanyId更适合放在INCLUDE中?


解答

核心原因在于查询的执行逻辑和数据分布特征,具体可以从以下几点理解:

  1. LEFT JOIN的执行顺序影响
    这个查询是从Company主表出发做LEFT JOIN,优化器大概率会先扫描Company表,再用每条数据的Company.Id去匹配CompanyTransaction表的记录。这种场景下,Type='SR'和Code=1000是强过滤条件——如果这两个值的组合在CompanyTransaction表中占比极低,优化器会优先用这两个键列快速定位到极小范围的数据集,再在这个小范围内匹配CompanyId,整体IO成本更低。

  2. 索引有序性的利用效率

    • 若把CompanyId放在键列最前面,索引的有序性是按CompanyId→Type→Code排列的。但主表Company的Id可能分布分散,优化器需要遍历大量不同CompanyId对应的索引分支,再过滤Type和Code,遍历成本很高。
    • 而以Type→Code作为键列的索引,叶子节点是按这两个值有序排列的,SQL Server可以快速定位到所有符合Type='SR'且Code=1000的行(因为键列有序,能直接跳转到目标区间),再通过INCLUDE里的CompanyId和主表做匹配,不需要回表,效率更高。
  3. 缺失索引建议的评估逻辑
    SQL Server的缺失索引建议是基于查询的预估执行计划生成的,它会计算不同索引的IO、CPU成本。如果Type+Code的过滤性足够强,对应的索引叶子节点数据量极小,即使要在其中匹配CompanyId,整体成本也远低于以CompanyId开头的索引。

最后可以通过查看实际执行计划,对比两个索引的逻辑读取数、执行时间,来验证哪个更适配你的真实数据分布。


内容的提问来源于stack exchange,提问作者Murphybro2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 16:05:09