聚集索引和非聚集索引
一、mysql索引分三类
B+树索引、Hash索引、全文索引
myisam和innodb两种存储引擎的底层数据结构都是B+树
hash索引能快速精准地定位,和B+树索引同时存在,作为B+树索引的配合,hash索引是系统自动生成的
二、一个表中如果没有创建索引,还会创建B+树嘛
会,如果在创建表时指定了主键,会用主键创建聚集索引;如果没有主键,系统会自动创建一个隐式主键作为聚集索引,但只供系统内部使用,用户无法访问
三、B+树的原理
每一页是16K的大小,B树在每一页中既存储了主键(索引值),也存储了每一行的数据;B+树只存储了主键,只在最叶子节点中存储了每行的数据
最上方绿色方块代表这行记录的类型(1代表非叶子节点),第二个方块代表记录的下一条记录,彩色的是具体的每行数据
非叶子节点中只存储相应的id和id存储的具体的页数
四、聚集索引和非聚集索引的区别
innodb中,主键索引(聚集索引):
在 InnoDB 中,表数据文件本身(.ibd 文件)就是按主键索引构建的一棵 B+Tree。页内的记录是按照主键的大小顺序排成一个单向链表,页和页之间也是根据页中记录的主键的大小顺序排成的一个双向链表。B+Tree 的叶子节点包含了完整的行数据,非叶子节点记录的是主键+页号
优点:数据访问快,因为索引和数据保存在同一个B+树中,因此从聚集索引中获取数据比非聚集索引更快。聚集索引对于主键的排序查找和范围查找速度非常快。按照聚集索引排列顺序,查询显示一定范围数据的时候,由于数据都是紧密相连,数据库可以从更少的数据块中提取数据,节省了大量的IO操作。
缺点:插入速度严重依赖于插入顺序,按照主键的插入顺序是最快的,否则将会出现页分裂,严重影响性能。因此对于innodb表我们一般都会定义一个自增的ID列为主键。更新主键的代价很高,因为将会导致被更新的行移动,因此对于innodb表我们一般定义主键为不可更新。为了充分利用聚集索引的特性,innodb表的主键应该选择有序的id,不建议使用无序id,比如UUID\MD5\HSH\ 字符串等,无法保证数据的顺序增长。
innodb中,辅助索引(非聚集索引):
除了主键索引以外的所有索引(如 UNIQUE, INDEX)都叫辅助索引。辅助索引也是 B+Tree 结构,但它的叶子节点存储的不是完整数据,而是该行对应的主键值。当通过辅助索引查找数据时,引擎会在辅助索引的 B+Tree 中找到对应的主键值。然后拿着这个主键值,再回到主键索引(聚集索引)的 B+Tree 中查找完整的行数据。这个过程被称为 回表查询。它比直接通过主键查询多了一次索引查找。
myisam中:
MyISAM 将数据和索引完全分开存储:
数据文件:.MYD 文件,表数据在 .MYD 文件中没有任何特殊的存储顺序,是堆文件(数据行简单地堆在一起)。
索引文件:.MYI 文件
所有索引都是非聚集索引,所有索引的 B+Tree 的叶子节点存储的都是数据行在 .MYD 文件中的物理地址。通过索引查找时,先找到这个物理地址,然后再去 .MYD 文件中的对应位置读取数据行。
五、myisam和innodb的区别
| 对比项 | myisam | innodb |
| 外键 | 不支持 | 支持 |
| 事务 | 不支持 | 支持 |
| 行表锁 | 表锁,即使操作一条记录也会锁住整个表,不适合高并发的操作 | 行锁,操作时只锁某一行,不对其他行有影响,适合高并发的操作 |
| 缓存 | 只缓存索引,不缓存真实数据 | 不仅缓存索引还要缓存真实数据。对内存要求较高,且内存大小对性能有决定性影响 |
| 关注点 | 并发查询,节省资源、消耗少、简单业务 | 并发写、事务、多表关系、更大资源 |
六、平衡二叉树、红黑树的区别是什么?
普通二叉树有可能左子树或右子树全部为空,退化成一个单链表,不能发挥二叉树的优势,解决方式就是平衡二叉树。找到中间的节点,将其变成根节点,保证左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
平衡二叉树每个节点记录一个数据。IO操作的效率很低,在大量数据存储中,查询时我们不能一下子将所有的数据全部加载到内存中,只能逐节点加载,如果采用平衡二叉树作为索引结构,那么磁盘的IO次数和索引树的高度是相关的,平衡二叉树由于树深度过大而造成IO读写过于频繁,进而导致效率低下。为了提高查询效率,就要减少磁盘IO次数,就要尽量降低树的高度,需要把原来瘦高的树结构变的矮胖,树的每层的分叉越多越好。
红黑树,存储网络地址、hashmap存储中都是使用红黑树;能两次旋转达到平衡;分为红节点和黑节点;容忍度比较高,允许更多的节点产生在一边;小范围的自旋。
【补充】
磁盘的速度远远慢于内存,而索引树(特别是B+树)的设计目标就是最小化昂贵且缓慢的磁盘I/O次数。
为什么磁盘I/O如此昂贵?
内存:访问速度快(纳秒级别),但断电后数据丢失,且价格昂贵。
磁盘(特别是机械硬盘HDD):访问速度慢(毫秒级别),但数据持久化,价格便宜。
磁盘的机械操作(磁头寻道、盘片旋转)非常耗时。一次磁盘I/O(读取或写入一个数据块)的时间,足够内存进行数十万次操作。因此,数据库系统的性能瓶颈往往不在于CPU计算速度,而在于磁盘I/O的速度。优化数据库性能的关键,就变成了如何尽量减少磁盘I/O次数。
一个节点的容量通常设计得正好等于磁盘页的大小(如4KB, 16KB)。这样,每次读取一个节点,正好对应一次磁盘I/O。
树的高度如何决定I/O次数?
根节点到任意一个叶子节点的路径长度是相等的,这个长度就是树的高度(h)。进行一次等值查询(如id = 100)的流程如下:
1. 第一次I/O:把根节点从磁盘读入内存。在内存中(速度极快)进行二分查找,确定id=100应该位于哪个子节点(指针P1)。
2. 第二次I/O:根据P1,把对应的内节点从磁盘读入内存。再次在内存中进行二分查找,找到下一个子节点的指针P2。
3. 重复这个过程...
4. 第h次I/O:把最终的叶子节点从磁盘读入内存。在叶子节点中查找,找到id=100对应的数据记录(或数据记录的指针)。
