Skip to content

在什么情况下,不推荐为数据库建立索引? ​

  • 标签:MySQL、后端、数据库

🏛 业务架构师 ​

不推荐建索引的场景,我按**"建了是负资产"的逻辑**列:

  • 低选择性列:性别、状态、布尔标记——几千行里筛出一半,索引回表代价比全表扫还高,优化器自己都会放弃。正确姿势是与其他高选择性条件组合成联合索引;
  • 极少被查询的列:为"一年跑两次的报表"建索引——读一次的收益付一年的写税,报表走从库/临时索引/ES;
  • 频繁更新的列:每次 update 都要维护 B+ 树(页分裂、调整)——写热列建索引是给写入上枷,比如计数器字段(点赞数经常变,用单独计数字段而非索引检索目标);
  • 小表:几百行的字典表全表扫描比走索引还快(数据都在一页里)——小表建索引纯属仪式感;
  • 一次性/低频批量任务的查询:跑批的查询优化优先改 SQL 写法或走分析库,不为离线任务污染在线表的索引结构;
  • 区分度极低的组合:如 (status, deleted) 组合几乎不筛掉数据——联合索引要保证整体选择性。

背后的决策模型:索引的收益 = 查询频率 × 性能提升幅度,成本 = 写入频率 × 维护开销 + 空间 + 优化器负担。收益覆盖不了成本就不建——这是一个期望值计算,不是"建了总没错"的安全癖。

治理补充:存量索引定期审计(使用率统计),砍掉没人用的索引和砍代码一样有价值——索引台账 + 季度盘点是我推行的机制。一句话:索引宁缺毋滥,为高频买单,不为焦虑买单。

🏗 系统架构师 ​

不推荐建索引的场景(本质都是"读收益 < 写代价/空间代价"):

  • 频繁更新且极少查询的表:日志写入表、流水表——每个索引都是写放大,写入 TPS 优先;
  • 区分度极低的列:性别、状态只有两三个值——索引选择性差,优化器大概率弃用(回表代价高于全表扫),白付维护成本;除非组合进联合索引做前缀过滤;
  • 小表:几百行的字典表,全表扫描比走索引还快(一次顺序 IO),索引纯属负担;
  • 写多读少的中间表/临时表:批量 ETL 的 staging 表,用完即弃;
  • 数据仓库/分析表的高频批量导入:导入前删索引、导完重建,比带索引写快一个量级(ETL 标准操作);
  • 长字符串列直接索引:UUID、长 text——索引体积膨胀,应改前缀索引(index(col(20)))、哈希列索引或改造主键;
  • 低频长尾查询:一个月跑一次的运营查询,走从库/临时加索引,不值得常驻索引拖累线上写入。

判断框架:建索引决策 = 查询频率 × 性能收益 vs 写入频率 × 维护代价 + 空间成本。没有数值直觉时,用 sys.schema_index_statistics 看已有索引的读写比——大量"只写不读"的索引就是应该删掉的对象。

💻 全栈开发专家 ​

核心判断:索引服务于查询,查询没有/不值得优化的表别建。我的"不建"清单:

  1. 区分度极低的列:性别、状态(两三个值)——优化器大概率放弃走索引,或走了反而更慢(回表代价高)。例外:状态字段配合其他列进联合索引没问题。

  2. 频繁更新且很少被查询的列:每次 update 都要维护 B+ 树,写放大换不来读收益。

  3. 写多读少的表:日志表、流水表、消息记录——插入是主要负载,索引越少写入越快;查询走归档库/ES。

  4. 小表:几百行的配置表,全表扫描比走索引还快(整表就在一两个页里);优化器也会自己放弃索引。

  5. 几乎不用的查询条件:上线一年没人按这个字段查——没有查询诉求的索引是纯负债。

  6. 表结构上不该建的:

    • 超长字符串全列索引 → 用前缀索引;
    • 已有 (a,b) 还建 (a) 的冗余索引;
    • 一张表十几二十个索引的历史包袱(先治理再新增)。

替代方案:低频的复杂查询(多条件 OR、模糊)交给 ES/ClickHouse;统计走数仓;超大表做归档后再查询。

决策一句话:**加索引前问三遍——哪个查询用它?扫描行数能降多少?写入能承受多少损耗?**答不上来就不建。