|
| 1 | +> 这个问题简单回答一下即可 |
| 2 | +
|
| 3 | +面试官:MySQL的引擎都有哪些? |
| 4 | + |
| 5 | +我:我知道,MySQL内部可以分为服务层和存储引擎层两部分:**服务层包括连接器、查询缓存、分析器、优化器、执行器等;存储引擎层负责数据的存储和提取**。我就说一下自己了解的InnoDB和MyISAM引擎 |
| 6 | + |
| 7 | +**InnoDB**: |
| 8 | + |
| 9 | +- 是 MySQL 默认的**事务型存储引擎**,只有在需要它不支持的特性时,才考虑使用其它存储引擎。 |
| 10 | +- 实现了四个标准的隔离级别,默认级别是**可重复读(REPEATABLE READ)**。在可重复读隔离级别下,通过**多版本并发控制**(MVCC)+ (Next-Key Locking)**防止幻影读**。 |
| 11 | +- 主索引是**聚簇索引**,在**索引中保存了数据**,从而避免直接读取磁盘,因此对查询性能有很大的提升。 |
| 12 | +- 内部做了很多优化,包括从磁盘读取数据时采用的**可预测性读**、能够加快读操作并且自动创建的**自适应哈希索引**、能够加速插入操作的**插入缓冲区**等。 |
| 13 | +- 支持真正的**在线热备份**。其它存储引擎不支持在线热备份,要获取一致性视图需要停止对所有表的写入,而在读写混合场景中,停止写入可能也意味着停止读取。 |
| 14 | + |
| 15 | +**MyISAM**: |
| 16 | + |
| 17 | +- 设计简单,数据以**紧密格式存储**。对于只读数据,或者表比较小、可以容忍修复操作,则依然可以使用它。 |
| 18 | +- 提供了大量的特性,包括**压缩表、空间数据索引**等。 |
| 19 | +- **不支持事务**。 |
| 20 | +- **不支持行级锁,只能对整张表加锁**,读取时会对需要读到的所有表加共享锁,写入时则对表加排它锁。但在表有读取操作的同时,也可以往表中插入新的记录,这被称为并发插入(CONCURRENT INSERT)。 |
| 21 | + |
| 22 | +我一般还会回答一个**索引文件**上的区别 |
| 23 | + |
| 24 | + |
| 25 | + |
| 26 | +**MyISAM**: |
| 27 | +1. MyISAM**索引文件和数据文件是分离**的,**索引文件仅保存数据记录的地址**,同样使用B+Tree作为索引结构,叶节点的**data域存放的是数据记录的地址** |
| 28 | +2. 在MyISAM中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求key是唯一的,而辅助索引的key可以重复 |
| 29 | +3. MyISAM中索引检索的算法为**首先按照B+Tree搜索算法搜索索引**,**如果指定的Key存在,则取出其data域的值,然后以data域的值为地址,读取相应数据记录** |
| 30 | + |
| 31 | +**InnoDB**: |
| 32 | +1. **InnoDB的数据文件本身就是索引文件**,这棵树的叶节点**data域保存了完整的数据记录**(聚集索引) |
| 33 | +2. InnoDB的**辅助索引data域存储相应记录主键的值而不是地址** |
| 34 | +3. **聚集索引这种实现方式使得按主键的搜索十分高效**,**但是辅助索引搜索需要检索两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录**。 |
| 35 | + |
| 36 | +其实个人还知道一点,分页查询的时候还有一点区别,这点区别也是根据索引文件的区别来的。 |
| 37 | + |
| 38 | +咱们知道,使用limit分页查询,offset越大,性能越差,比如: |
| 39 | + |
| 40 | +```sql |
| 41 | +-- 以真实的生产环境的6万条数据的一张表为例,比较一下优化前后的查询耗时: |
| 42 | +-- 传统limit,文件扫描 |
| 43 | +select * from table order by id limit 50000,2; |
| 44 | +受影响的行: 0 |
| 45 | +时间: 0.171s |
| 46 | + |
| 47 | +-- 子查询方式,索引扫描 |
| 48 | +select * from table |
| 49 | +where id >= (select id from table order by id limit 50000 , 1) |
| 50 | +limit 2; |
| 51 | +受影响的行: 0 |
| 52 | +时间: 0.035s |
| 53 | + |
| 54 | +-- JOIN分页方式 |
| 55 | +select * from table as t1 |
| 56 | +join (select id from table order by id limit 50000, 1) as t2 |
| 57 | +where t1.id <= t2.id order by t1.id limit 2; |
| 58 | +受影响的行: 0 |
| 59 | +时间: 0.036s |
| 60 | +``` |
| 61 | + |
| 62 | +原因:因为 MySQL 并非是跳过偏移量直接去取后面的数据,而是先把偏移量+要取的条数,然后再把前面偏移量这一段的数据抛弃掉再返回的。比如上面的(50000,2),每次取2条,还要经过回表,发现不是想要的,舍弃。那肯定非常耗时间,而通过子查询通过id索引,只查询id,使用到了innodb的索引覆盖, 在内存缓冲区中进行检索,没有回表查询. 然后再用id >= 条件,进一步的缩小查询范围.这样就大大提高了效率。 |
| 63 | + |
| 64 | +而MyISAM,是直接索引是分离的,通过索引文件查到的数据记录地址,不需要回表,直接对应数据记录,效率也很高。 |
0 commit comments