一、简述
InnoDB的细粒度行锁以及事务支持是MySQL吸引人的重要特性。但,不当的使用会使InnoDB的行级锁变成表级锁,给我们带来较大的困扰(select、update、delete都可能导致表级锁)。
二、索引类型
InnoDB的索引有两类:聚集索引(Clustered Index)与普通索引(Secondary Index)。
InnoDB的每一个表都会有聚集索引。如果你没手动创建,InnoDB也会默认的帮你创建聚集索引。
聚集索引以下面三种形式存在:
- 如果表定义了PK(主键),则 PK 就是聚集索引;
- 如果表没有定义PK,则第一个非空unique列(唯一索引列)是聚集索引;
- 如果以上列都不存在,InnoDB会创建一个隐藏的 row-id 作为聚集索引。
三、索引结构
B+树中的B代表平衡(balance),而不是二叉(binary),因为B+树是从最早的平衡二叉树演化而来的。想了解的童鞋可以搜下二叉查找树、平衡二叉树(AVLTree)和平衡多路查找树(B-Tree),B+树由这些树逐步优化而来。
我们知道InnoDB索引的结构是B+树,这里不展开B+树的细节,先说几个结论:
- 在索引结构中,非叶子节点存储 key,叶子节点存储 value;
- 普通索引,叶子节点存储了 PK 的值;
- 聚集索引,叶子节点存储行记录(row)。
四、索引方式
由于上面我们说过的InnoDB的每一个表都会有聚集索引,索引结构中叶子节点存储 value,而聚集索引的叶子节点还会存储行记录(row)。所以,InnoDB 索引和记录是存储在一起的。
所以,InnoDB的普通索引,实际上会扫描两遍:第一遍,由普通索引找到 PK(定义为聚集索引列);第二遍,由PK找到行记录。
例:
简图说明:
id为PK的聚集索引,叶子存储了所有的行记录;
namepy为普通索引,叶子存储了PK的值;
当执行查询 select * from t where namepy=’zs’语句时,过程为:
先在namepy普通索引上查询到PK=1;
再在聚集索引上查询到(1,zs, 张三)的行记录;
理解:
InnoDB的细粒度锁,是实现在索引记录上的,若where没有命中索引,则会退化为表锁。
若上面的namepy并没有创建索引,则它会变成表锁。至于是读锁、写锁还是互斥锁则根据事务的隔离级别来确定。