InnoDB引擎表的主键选型

本文深入探讨了InnoDB存储引擎表主键的设计原则与实践,包括主键选择的要求、存储结构特点、主键优秀素质分析以及自增序列、UUID、注册账号、序列生成器作为主键的优缺点比较。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MySQL采用开放可插入式存储引擎架构,提供类似电源插线板的功能,其后接入的存储引擎就类似电器设备,而我们大家常用的存储以MyISAM和InnoDB为主,早期大家主要使用MyISAM引擎支持业务,随MySQL支持业务范围越来越广,存储的数据对企业越来越重要,尤其PC服务器支持的最大内存越来越大,内存的价格也越来越便宜,逐渐采用InnoDB引擎为主.二种风格迥异的存储引擎,各自内部存储算法和数据操纵实现等都竞相不同,另外InnoDB引擎与其他商业数据库产品存储引擎也不太相同,为此我们必须根据使用的存储引擎特点,设计合理的数据存储结构和数据操纵方式。本文将围绕InnoDB存储引擎的主键设计而展开,告诉大家怎样设计表的主键才是合理的做法。

讨论InnoDB引擎表的主键选型的要求之前,我们大家先简单温习下InnoDB引擎表的元数据和索引数据存储结构特点。

InnoDB引擎表的数据和索引都是存储在同一个文件中,InnoDB引擎的页大小默认为16K,且页空间使用率为15/16,为此每页能存储的数据量是有限的。主键和数据的关系是数据存储在簇索引的叶子节点中,接下来我们看下主键和数据的组织结构关系,如图1-1:


图 1-1

    对于非簇索引,又是如何存储的呢?通过翻译官方文章,得知:每个非簇索引的叶子节点存储的数据都包含簇索引的值,然后通过簇索引的值,可以查找到对应的元数据,我们继续看一下非簇索引的存储结构,以及与簇索引之间的关系,如图1-2:


图 1-2

紧接着,我们来理清楚InnoDB引擎表的簇索引为哪三类:

l  主键也即是我们文章说的簇索引;

l  若表中无主键,但是存在唯一索引,且字段定义为非空,则作为簇索引;

l  表无主键,也无 非空唯一索引,则内部默认隐含性创建一个长度为6个字节的字段作为簇索引字段;

通过上述探讨和分析,弄清楚了数据存储页的空间值和利用率、簇索引和非簇索引的存储结构,以及簇索引和元数据、簇索引和非簇索引的存储关系,以及簇索引为哪三类,那么我们建议大家一定要为InnoDB引擎表创建一个主键,没必要搞一个唯一性索引且字段定义属性非空,而不创建主键的表结构,我们再分析优秀主键具备的素质:值域范围够用且存储长度越短、值的唯一性和易比较性、数值的有序性增加,三个素质的各自优点,单独详细分析。

主键的值域够用且长度越短,将产生三个方面的优势

(1).     相同数据行数的表,数据容量越小,占用磁盘空间越少,为此可以节约物理或逻辑IO和减少内存占用;

(2).     普通索引的长度也将更短,可以减少通过普通索引搜索数据的物理或逻辑IO;

(3).     减少索引数据存储的页块裂变,从而提高页的利用率,以及减少物理IO;

主键的唯一性

(1).     主键的值要求必须唯一,且非空;

(2).     主键值每次插入或修改,都必须判断是否有相同值,为此减少索引值需要比对的长度,可以提高性能,或者间接地让其转换成比对数值大小的方式,提高其比对判断的效率;

主键值插入的有序性,将产生二个方面的优势

(1).     主键存储的块与块之间是有序的,然后块内有也是有序的,主键值的有序插入,可以减少块内的排序,节约磁盘物理IO;

(2).     主键值的有序性,可以提高数据舒顺序取速度,提高服务器的吞吐量,也可以节约物理IO;

上述讨论的数据存储结构及关系,以及主键字段要求的素质等理论知识之外,我们还需要考虑实际生产环境的业务、架构等综合因素,我们实际生产环境可能会使用四类属性作为主键:

(1).     自增序列;

(2).     UUID()函数生成的随机值;

(3).     用户注册的唯一性帐号名称,字符串类型,一般长度为:40个字符;

(4).     基于一套机制生成类似自增的值,比如序列生成器

那么我们接下来,再分析下这四类属性各自作为表主键的优缺点:

(1).     自增序列:从小到大 或从大到小的顺序模式增加新值;数据类型也利于进行主键值比较;存储空间占用也相对最小,一般设置为:4个字节的INT类型或 8个字节的BIGINT类型;若是想进行数据水平拆分的话,也可以借助设置mysqld实例的2个参数:auto_increment_increment 和 auto_increment_offset;另外,唯一缺点就是自增序列是一个表级别的全局锁,在5.0系列大规模并发写的时候,因锁释放机制的问题容易出现瓶颈,但是5.1系列做了改进,基本上不存在此问题;

(2).     UUID()函数:值为随机性+固定部分,其值产生是无序的,且同一台服务器上产生的值相同部分为77.8%;产生的值字符个数为36,按utf8编码计算,占用的存储空间为36个字节;对于数据水平拆分支持,无需特殊设置;

(3).     使用用户注册的帐号名称,字符串类型,其值的产生依赖用户输入,为此数据基本上为无序增加,字符串的长度也是不定的,只能通过前段技术控制最短最大长度值的限制,对水平拆分支持,无需做特殊设置;

(4).     序列生成器的架构,类似自增序列,不过需要借助额外的开发工作量,以及提供一个第三方的服务,可以规避自增序列的字增全局锁的问题,提高并发,对数据水平拆分可以更好地支持;

(5).     双主复制架构的概率性碰到的场景:主服务器的数据执行成功,而没有复制到在线备用服务器时,出问题的概率确实存在,其他类型的做法,也必须人工干涉解决,都无简单且合理的自动化办法,以上四种办法都无法规避;

通过四种属性值作为主键的优缺点分析,以及对比前面我们阐述的主键需要的优秀素质,若是不考虑水平拆分的问题,带来额外设置上的麻烦,则自增序列是最佳的主键字段选择;用户的注册帐号本身要求唯一性且非空的场景下,则可以作为主键字段的选择;若是考虑水平拆分的问题,则采用自增序列生成器的架构,非常易用和可靠的实现方式,产生的值是最佳主键字段的选择;

结束

使用什么类型的字段属性作为主键,最关键核心的要考虑存储引擎:如何存储元数据、如何检索元数据、如何维护其内部的索引组织结构,以及我们要实现的业务是什么,最后共同决定我们,如何设计一张用于存储数据的表,以及决定操纵数据的SQL语句如何编写,再结合业务特点就决定了我们的索引如何创建,建议大家多关注InnoDB引擎内部实现原理和机制,可以阅读官方提供的一个文档InnoDB引擎内部实现,以及多分析和关注业务特点。

本文转自http://www.mysqlops.com/2011/09/10/innodb-primary.html

<think>嗯,用户想了解InnoDB和MyISAM存储引擎的区别,这个问题很经典但也很基础。用户可能是数据库初学者,或者正在做技术选型。从ta直接引用站内资料的行为看,ta应该已经查过一些资料,但需要更系统的对比。 用户引用的资料里已经覆盖了主要区别点:事务支持、锁机制、外键、存储结构等。不过引用[4]提到count(*)性能差异这个点需要特别注意——在无where条件时MyISAM确实快,但这个优势在现代MySQL版本中意义不大,因为实际业务很少会无条件count全。 我注意到引用[5]提到InnoDB的MVCC和间隙锁,这是高级特性但用户可能不理解。在解释时要避免术语堆砌,比如用“防止幻读”不如说“防止其他事务插入新数据影响当前查询结果”更易懂。 用户没提具体场景,但最后引用[3]提到选择建议,说明ta可能关心如何选型。所以除了罗列区别,还要强化适用场景的对比。比如电商订单系统必须用InnoDB,而内部日志分析用MyISAM也无妨。 需要纠正一个常见误解:很多人以为MyISAM读取更快,其实在缓冲池配置合理的情况下,InnoDB的读写性能并不差。这个点要在性能对比部分强调。 格对比是必须的,但要注意把核心差异放在前面:事务和崩溃恢复是本质区别,全文索引这种次要特性往后排。突然想到MySQL 8.0后InnoDB也支持全文索引了,要更新这个信息。 最后用户可能隐含担心迁移成本,虽然ta没直接问,但在总结部分可以提一句“从MyISAM切换到InnoDB需注意外键约束重建”。</think>以下是 InnoDB 与 MyISAM 存储引擎的核心区别对比及详细解析: --- ### 一、核心区别对比 | **特性** | **InnoDB** | **MyISAM** | |-------------------|-------------------------------------|---------------------------------| | **事务支持** | ✅ ACID 事务,支持 Commit/Rollback | ❌ 不支持事务 | | **锁机制** | 行级锁(默认),支持间隙锁 | 级锁 | | **外键约束** | ✅ 支持外键 | ❌ 不支持外键 | | **崩溃恢复** | ✅ 通过 redo log 实现崩溃安全 | ❌ 数据易损坏 | | **MVCC** | ✅ 多版本并发控制 | ❌ 不支持 | | **全文索引** | ✅ MySQL 5.6+ 支持 | ✅ 原生支持 | | **存储文件** | `.ibd`(数据+索引) | `.MYD`(数据)+ `.MYI`(索引) | | **COUNT(*) 性能** | 需全扫描(无缓存时) | 直接读取元数据,极快 | | **适用场景** | 高并发写入、事务型应用(如支付、订单)| 读密集型应用(如日志分析、数据仓库) | --- ### 二、关键特性详解 #### 1. **事务与 ACID 特性** - **InnoDB**: 支持完整的事务(BEGIN/COMMIT/ROLLBACK),通过 **undo log** 实现回滚,**redo log** 保证持久性[^2][^5]。 示例:转账操作需原子性,必须使用 InnoDB。 - **MyISAM**: 每次操作直接写入磁盘,无法回滚。系统崩溃时可能丢失数据或损坏[^1][^4]。 #### 2. **锁机制与并发控制** - **InnoDB**: - **行级锁**:仅锁定被修改的行,其他行可并发读写。 - **间隙锁(Gap Lock)**:防止幻读,锁定索引范围(如 `WHERE id BETWEEN 10 AND 20`)[^5]。 - **MyISAM**: **级锁**:写操作时锁定整张,阻塞所有读写请求,并发性能差[^1][^4]。 #### 3. **数据存储结构** | **引擎** | **文件结构** | **特点** | |-----------|----------------------------------|---------------------------------------------| | **InnoDB**| `.ibd` 文件(每独立) | 数据与索引聚合存储(聚簇索引) | | **MyISAM**| `.MYD`(数据)+ `.MYI`(索引) | 数据与索引分离,索引通过指针指向数据位置 | > ⚠️ **InnoDB 聚簇索引优势**: > 主键索引的叶节点直接存储行数据,减少磁盘 I/O(如 `SELECT * FROM users WHERE id=1` 只需 1 次检索)[^1][^5]。 #### 4. **性能对比** | **操作** | **InnoDB** | **MyISAM** | |----------------|-------------------------------|--------------------------| | **SELECT** | 接近 MyISAM(缓冲池优化后) | ⭐⭐⭐⭐⭐ 极快 | | **INSERT/UPDATE**| ⭐⭐⭐⭐ 行级锁支持高并发 | ❌ 锁阻塞严重 | | **COUNT(*)** | 慢(需扫描或二级索引) | ⚡ 直接读取 `.MYI` 计数 | | **全文索引** | ✅ 可用但性能低于 MyISAM | ⭐⭐⭐⭐ 优化更好 | #### 5. **崩溃恢复** - **InnoDB**: 通过 **redo log** 重放未落盘的操作,保证数据一致性[^5]。 ```sql -- 检查恢复状态 SHOW ENGINE INNODB STATUS; ``` - **MyISAM**: 崩溃后需执行 `CHECK TABLE` 和 `REPAIR TABLE`,可能丢失数据[^4]。 --- ### 三、选型建议 | **场景** | **推荐引擎** | **原因** | |-------------------------|--------------|---------------------------------------------| | 支付/订单系统 | InnoDB | 事务安全,高并发写入 | | 数据仓库(只读报) | MyISAM | COUNT(*) 快,节省内存 | | 博客系统(早期 WordPress)| MyISAM | 读多写少,全文索引需求 | | 高并发 OLTP | InnoDB | 行级锁避免阻塞 | > 💡 **现代实践建议**: > MySQL 5.5+ 默认使用 InnoDB,因其在并发性能、数据安全性上全面优于 MyISAM[^3]。MyISAM 仅适用于只读或低写入场景。 --- ### 四、迁移示例(MyISAM → InnoDB) ```sql -- 检查当前引擎 SHOW TABLE STATUS LIKE 'orders'; -- 转换引擎(需锁定) ALTER TABLE orders ENGINE = InnoDB; -- 验证外键约束 SELECT * FROM information_schema.TABLE_CONSTRAINTS WHERE TABLE_NAME = 'orders'; ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值