Carry の Blog Carry の Blog
首页
  • Nginx
  • Prometheus
  • Iptables
  • Systemd
  • Firewalld
  • Docker
  • Sshd
  • DBA工作笔记
  • MySQL
  • Redis
  • TiDB
  • Elasticsearch
  • Python
  • Shell
  • MySQL8-SOP手册
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Carry の Blog

好记性不如烂键盘
首页
  • Nginx
  • Prometheus
  • Iptables
  • Systemd
  • Firewalld
  • Docker
  • Sshd
  • DBA工作笔记
  • MySQL
  • Redis
  • TiDB
  • Elasticsearch
  • Python
  • Shell
  • MySQL8-SOP手册
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • MySQL8-SOP

  • MySQL实战45讲学习笔记

    • MySQL45讲学习笔记
    • MySQL基础架构
    • MySQL日志系统 (Redo Log 与 Binlog)
    • MySQL字符串字段索引优化
    • MySQL索引原理与优化
    • MySQL锁机制详解
    • MySQL事务与MVCC机制
    • MySQL普通索引与唯一索引的选择
      • 1. 查询性能
      • 2. 更新性能 (Change Buffer)
      • 3. Change Buffer 的使用场景与效果
      • 4. 索引选择建议
      • 5. Change Buffer 与 Redo Log 的对比
    • MySQL优化器如何选择索引
    • MySQL抖动刷脏页
    • 表空间管理与回收
    • count函数详解
    • 日志索引
    • orderby工作原理
    • 随机排序实现
    • SQL性能差异函数与转换
    • 慢查询分析锁与版本
    • 幻读与间隙锁
    • 加锁规则分析
    • 应急性能优化方法
    • 数据持久化保证
    • 主备一致性原理
    • 高可用架构与切换
    • 备库延迟分析与优化
    • 主备切换GTID
    • 读写分离实践与问题
    • 数据库健康检查
    • 锁与死锁
    • 数据误删恢复
    • Kill命令详解
    • 查询与内存使用分析
    • Join原理与选择
    • 临时表原理与应用
    • 内部临时表详解
    • Memory引擎详解
    • 自增ID详解
    • Insert加锁分析
    • 表复制方法比较
    • Grant与权限管理
    • 分区表详解
    • SQL语句中的Join问题
    • 自增ID用尽问题
  • 专题系列
  • MySQL实战45讲学习笔记
Carry の Blog
2024-07-27
目录

MySQL普通索引与唯一索引的选择

# 普通索引与唯一索引的选择

在选择使用普通索引还是唯一索引时,主要需要考虑它们在查询性能和更新性能上的差异。

# 1. 查询性能

  • 等值查询:
    • 唯一索引: 找到满足条件的第一个记录后,直接停止搜索。
    • 普通索引: 找到满足条件的第一个记录后,还需要继续向后查找,直到碰到第一个不满足条件的记录。
  • 性能差异: 对于 InnoDB 引擎来说,数据是按数据页为单位读写的。当找到满足条件的记录时,它所在的数据页就已经在内存中了。对于普通索引,多做的那次“查找和判断下一条记录”的操作,只是简单的指针移动和 CPU 计算,速度非常快。因此,两者在查询性能上的差距微乎其微。

# 2. 更新性能 (Change Buffer)

这是两者性能差异的主要体现。

  • Change Buffer:

    • 定义: 当需要更新一个数据页时,如果该数据页不在内存 (Buffer Pool) 中,InnoDB 会将这个更新操作缓存在 Change Buffer 中(这是内存 Buffer Pool 的一部分),而不是立即从磁盘加载数据页进行更新。这样就避免了大量的随机 I/O。
    • 适用对象: 非唯一二级索引 (普通索引) 的更新操作(INSERT, DELETE, UPDATE)。
    • 不适用唯一索引: 因为唯一索引需要保证其唯一性约束,所以在插入或更新时,必须将数据页读入内存进行判断,看是否存在重复记录。因此,唯一索引的更新无法利用 Change Buffer。
    • Merge 操作: Change Buffer 中的操作并不会一直缓存。当下次有查询需要访问该数据页时,会将数据页读入内存,然后执行 (merge) Change Buffer 中与这个页相关的操作,以保证数据的逻辑正确性。系统后台线程也会定期进行 merge 操作,数据库正常关闭时也会执行 merge。
    • 持久化: Change Buffer 本身也是可以持久化的。它的变更也会记录到 redo log 中,所以即使数据库异常重启,Change Buffer 中的数据也不会丢失。
  • 性能影响:

    • 普通索引: 可以利用 Change Buffer,将对磁盘的随机写(更新数据页)转换为对 Change Buffer 的顺序写(可能还有 redo log 的顺序写),并在后续 merge 时批量处理,显著减少了随机 I/O,提升更新性能,尤其是在写多读少的场景。
    • 唯一索引: 无法利用 Change Buffer,每次更新都需要将数据页读入内存,进行随机 I/O,更新性能相对较低。

# 3. Change Buffer 的使用场景与效果

  • 适用场景:
    • 写多读少的业务:例如账单流水、日志记录等。更新操作可以先缓存,后续读取概率低,merge 操作可以延迟进行,优化效果明显。
    • 写入后不会立即读取的场景。
  • 不适用场景 (或效果差):
    • 写入后立即读取: 写入后马上查询该数据,会立即触发 merge 操作,不仅没有减少随机 I/O,反而增加了 Change Buffer 的维护代价。
    • 业务强制要求唯一性: 必须使用唯一索引。

# 4. 索引选择建议

  • 查询性能: 两者差别不大。
  • 更新性能: 普通索引由于可以利用 Change Buffer,通常更新性能更好。
  • 核心考量: 业务是否强制要求数据库层面保证唯一性。
    • 如果业务不要求或可以通过应用层逻辑保证唯一性,强烈推荐使用普通索引,以获得更好的更新性能。
    • 如果业务必须依赖数据库保证唯一性,则只能选择唯一索引。

# 5. Change Buffer 与 Redo Log 的对比

两者都是 InnoDB 用来提升性能的机制,但侧重点不同:

  • Redo Log: 主要目的是保证事务的持久性 (Crash-Safe)。它通过将随机的磁盘写操作(更新数据文件)转换为顺序的日志写操作,来提升性能和保证数据不丢失。节省的是随机写磁盘的 I/O 消耗。
  • Change Buffer: 主要目的是提升非唯一二级索引的更新性能。它通过缓存更新操作,避免了在数据页不在内存时立即进行的随机读操作。节省的是随机读磁盘的 I/O 消耗。

#MySQL#索引#普通索引#唯一索引#Change Buffer#性能优化#学习笔记
上次更新: 6/21/2025

← MySQL事务与MVCC机制 MySQL优化器如何选择索引→

最近更新
01
表空间管理与回收
06-21
02
MySQL抖动刷脏页
06-21
03
count函数详解
06-21
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式