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

同一列存在聚集主键与唯一索引是否必要?外键如何调整?

问题

近期使用Blitz查看索引数据时,发现Products表的唯一varchar(10)列(product_id)同时存在聚集主键与唯一非聚集索引。两者定义如下:

ALTER TABLE [dbo].[Products] 
    ADD CONSTRAINT [PK_Products_1] 
        PRIMARY KEY CLUSTERED ([product_id])
-- Usage: Reads: 1,503,413 (464,967 seek 16,534 scan 1,021,912 lookup) Writes:1,016,923
-- Size: 47,155 rows; 96.5MB; 5.6MB LOB

CREATE UNIQUE INDEX [IX_Products_1] 
    ON [dbo].[Products] ([product_id])
-- Reads: 1,663,103 (24,129 seek 1,638,974 scan) Writes:477
-- Size: 47,155 rows; 0.9MB

其中第二个非聚集索引被多个外键约束引用。请问:

  • 是否有必要同时保留这两个索引?
  • 当前的使用量与大小数据有何参考价值?
  • 是否应将外键改为引用聚集主键后删除该唯一非聚集索引?

分析与建议

1. 是否有必要同时保留两个索引?

完全没必要。聚集主键本身就具备唯一性,和这个唯一非聚集索引的键完全一致——都是product_id。从功能上看,两者都能保证product_id的唯一性,也都能支撑查找、外键关联等操作。保留两个键重复的索引纯粹是浪费存储资源,还会额外增加写入时的索引维护成本。

2. 使用量与大小数据的参考价值

  • 读取数据维度:
    • 聚集主键的读取记录里有大量lookup操作(102万+),说明很多查询通过非聚集索引(包括这个IX_Products_1)拿到主键后,需要回表获取其他列数据;而IX_Products_1的读取几乎全是scan(163万+),说明这个索引常被用来做全表扫描——但其实聚集主键也能完成同样的扫描逻辑,只是体积更大而已,本质上是重复的读取操作。
    • 两个索引的读取量都不低,但都是针对同一列的操作,没有必要分开维护。
  • 写入数据维度:
    • 聚集主键的写入量(101万+)远高于非聚集索引(477),这是因为聚集主键是表的物理存储结构,写入开销本身就大;而每次对product_id做插入/更新/删除时,两个索引都要同步维护,留着非聚集索引等于平白多了一份写入维护成本。
  • 大小数据维度:
    • 聚集主键占96.5MB是因为它包含了表的所有数据;非聚集索引仅0.9MB是因为只存储product_id(由于聚集键就是product_id,所以本质是重复存储了一份product_id)。哪怕体积小,也是无意义的重复存储,随着数据量增长,浪费会持续扩大。

3. 是否应将外键改为引用聚集主键后删除该唯一非聚集索引?

推荐这么操作,具体原因:

  • 外键约束本来就应该关联主键(主键的核心作用之一就是作为关联的唯一标识),将外键改为引用PK_Products_1完全符合数据库设计规范。
  • 修改外键后删除IX_Products_1,可以直接节省0.9MB的存储,同时消除每次写入时维护这个索引的额外开销。
  • 操作前注意点:可以先将IX_Products_1设为禁用状态,观察一段时间,确认没有业务查询依赖该索引后再正式删除——从现有读取数据看,该索引的操作以扫描为主,换成聚集主键的扫描不会影响功能,只会有极轻微的性能差异(因为聚集主键体积更大),完全在可接受范围内。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 07:16:09