存储方式
InnoDB 中,聚簇索引的叶子节点直接存储完整数据行,数据按主键值物理排序存储。
示例存储结构
B+树结构:
根节点 → [id<100, page1] [100≤id<200, page2]
叶子节点(page1)→ | id=50 | Alice | 25 | → | id=80 | Bob | 30 |
(数据行按id排序存储)
查询类型 | 聚簇索引性能 | 非聚簇索引性能 |
---|---|---|
主键查询 | ⚡️ O(1) 直接定位数据 | 需两次查找(索引+回表) |
范围查询 | ⚡️ 顺序I/O快(数据连续存储) | 随机I/O多(数据分散) |
覆盖查询 | ✅ 无需回表 | 若索引包含查询字段可避免回表 |
结论:主键查询优先使用聚簇索引,二级索引需评估回表代价
核心作用
存储结构
┌───────────────┐
| Undo Log Segment |
| - INSERT → 记录主键值 |
| - UPDATE → 旧数据镜像 |
| - DELETE → 数据完整拷贝 |
└───────────────┘
核心作用
确保事务持久性,防止数据丢失
工作流程
要素 | 说明 |
---|---|
隐藏字段 | DB_TRX_ID (最后修改事务ID)、DB_ROLL_PTR (回滚指针指向旧版本) |
版本链 | 数据通过回滚指针形成多版本链 |
ReadView | 决定事务可见哪个版本(包含活跃事务ID列表) |
def is_visible(trx_id, read_view):
if trx_id < read_view.min_trx_id:
return True # 已提交的旧事务
elif trx_id in read_view.active_trx_ids:
return False # 未提交的活跃事务
else:
return trx_id <= read_view.creator_trx_id
隔离级别 | MVCC 行为 |
---|---|
读已提交(RC) | 每次查询生成新 ReadView |
可重复读(RR) | 事务内复用同一个 ReadView |
锁类型 | 描述 | 应用场景 |
---|---|---|
共享锁(S Lock) | 允许其他读锁,阻塞写锁 | SELECT ... LOCK IN SHARE MODE |
排他锁(X Lock) | 阻塞其他所有锁 | SELECT ... FOR UPDATE |
间隙锁(Gap Lock) | 锁定索引记录间的间隙 | 防止幻读(RR级别) |
Next-Key Lock | 行锁+间隙锁组合 | 同时防止幻读和写冲突 |
隔离级别 | 实现机制 | 典型场景 |
---|---|---|
读未提交(RU) | 无锁直接读最新数据 | 实时统计 |
读已提交(RC) | 语句级快照读 + 行锁 | 高并发OLTP |
可重复读(RR) | 事务级快照读 + Next-Key Lock | MySQL默认级别 |
串行化(Serial) | 全表范围锁 + 严格串行执行 | 金融交易 |
-- 事务1
BEGIN;
UPDATE accounts SET balance=balance-100 WHERE id=1; -- 获得X锁
UPDATE accounts SET balance=balance+100 WHERE id=2; -- 等待事务2释放锁
-- 事务2
BEGIN;
UPDATE accounts SET balance=balance-50 WHERE id=2; -- 获得X锁
UPDATE accounts SET balance=balance+50 WHERE id=1; -- 等待事务1释放锁
-- InnoDB 检测到死锁后,自动回滚代价较小的事务
-- 有效使用索引
SELECT * FROM users WHERE name='Alice' AND age>20;
-- 索引设计为 (name, age)
SET autocommit=0;
INSERT INTO big_table VALUES (...); -- 执行1000次
COMMIT;
WHERE id=123
(比范围查询更高效)SET innodb_lock_wait_timeout=3; -- 锁等待超时3秒
通过深入理解存储引擎机制,可针对性优化数据库设计,提升系统并发性能与数据可靠性。