1. MySQL中innodb和myisam的区别
- myisam是5.1之前的默认引擎,支持全文检索、压缩、空间函数等。
- mysiam不支持事务和行级锁,所以一般用于大量查询和少量插入的场景使用
- mysiam不支持外键,并且索引和数据是分开存储的
innodb是基于聚簇索引建立的
索引按数据结构划分为:B+树和hash索引
- B+树是左小右大的顺序存储结构,节点只包含id索引列,而叶子节点包含索引列和数据,这种数据和索引在一起存储的索引方式叫做聚簇索引。一张表只能有一个聚簇索引。
- 假设没有定义主键,innodb会选择一个唯一的非空索引来替代,如果没有的话则会隐式指定一个主键作为聚簇索引。
- innodb中,在聚簇索引之上创建的索引称之为辅助索引,辅助索引访问数据总是需要二次查找。辅助索引叶子节点上存储的不再是行的物理位置,而是主键值。
- 非聚簇索引
- 将数据存储与索引分开结构,索引结构的叶子节点指向了数据的对应行,myisam通过key_buffer把索引先缓存到内存中,当需要访问数据时(通过索引访问数据),在内存中直接搜索索引,然后通过索引找到磁盘相应数据。这也就是为什么索引不在key_buffer命中时,速度慢的原因。
3. 覆盖索引和回表
覆盖索引
MySQL的锁分为表锁和行级锁,也叫做读锁和写锁
- 读锁是共享的,可以通过lock in share mode实现,这时候只能读不能写
- 写锁是排它锁,他会阻塞其他的写锁和读锁。从颗粒度来区分,可以分为表锁和行锁。
写锁
A:原子性
- 一个事务的操作要么全部成功,要么全部失败
- C:一致性
- 一个事务执行前后,数据库的完整性约束没有被破坏
- I:隔离性
- 当多个用户并发访问数据库时,比如同时访问一张表,数据库每一个用户开启的事务不能被其他事务所作的操作干扰,多个并发事务之间,应当相互隔离
- D:持久性
- 事务执行成功后,该事务对数据库的更爱是持久地保存在数据库中过的
隔离性有四个级别
- read uncommit 读未提交,可能会读到其他事务未提交的数据,也叫脏读。
- 用户本来应该读到id=1的用户age应该是10,结果读到了其他事务还没有提交的事务,结果读到结果age=20,这就是脏读。
- read commit 读已提交,两次读取结果不一样,叫做不可重复读。
- 不可重复读解决了脏读的问题,他只会读取已经提交的事务。
- 用户开启事务读取id=1用户,查询到age=10,再次读取发现结果=20,在同一个事务里同一个查询读取到不同的结果叫做不可重复读。
- repeated read 可重复读,这是MySQL的默认级别,就是每次读取结果都不一样,都是有可能产生幻读
serializable 串行,一般不会使用,他会给每一行读取的数据加锁,会导致大量超时和锁竞争问题。
6. ACID靠什么保证
A原子性:是undo log日志保证的,他记录了需要回滚的日志信息,事务回滚时撤销已经执行成功的sql
- C一致性:一般由代码层面保证
- I隔离性:由MVCC来保证
D持久性:由内存和redo log保证,MySQL修改数据同时在内存和redo log 记录这次操作,事务提交的时候通过redo log 刷盘,宕机的时候可以从redo log恢复。
7. 什么是幻读,什么是MVCC
要说幻读,首先要了解MVCC,MVCC叫做多版本并发控制,实际上就是保存了数据在某个时间节点的快照。
- 我们每行数实际上隐藏了两列,创建时间版本号,过期(删除)时间版本号,没开始一个新的事务,版本号都会自动递增。
-
8. 什么是间隙锁
间隙锁是可重复读级别下才有的锁,结合MVCC 和间隙锁可以解决幻读的问题。
9. 分库分表是怎么做的
分库分表分为垂直和水平两个方式,拆分的顺序是先垂直后水平。
- 垂直分库
- 订单 用户 商品 支付 预算
- 垂直分表
- 如果表字段比较多,将不常用的、数据较大的等等做拆分
- 把订单表分为基础信息、订单扩展和收货地址
-
10. 分表后的id怎么保证唯一性的
因为我们的主键默认是自增的,那么分表之后的主键在不同的表中肯定会有冲突。几个解决方法如下:
设定步长,比如1-1024张表我们分别设定1-1024的基础步长,这样主键落到不同的表就不会冲突了。
- 分布式ID,自己实现一套分布式ID生成算法或是使用开源的比如雪花算法
分表后不使用主键作为查询依据,而是每张表单独新增一个字段作为唯一主键使用,比如订单表订单号是唯一的,不管最终落在哪张表都是基于订单号作为查询依据,更新也一样。
11. MySQL主从同步是怎么做的
MySQL主从同步的原理
master提交事务后,写如binlog
- slave 连接到master,获取binlog
- master创建dump线程,推从binlog到slave
- slave启动一个IO线程读取同步过来的master的binlog,记录到relay log中继日志中
- slave 记录自己的binlog

MySQL默认的复制方式是异步的,主库把日志发送从库后就不关心是否已经处理,这样这样会产生一个问题就是假设主库挂了,从库处理失败了,这时候从库升为主库,日志就丢失了。两个方法:
- 全同步复制
- 主库写入binlog后强制同步日志到从库,所有的从库都执行完成后才返回给客户端,这个性能会受到影响
- 半同步复制
- 从库写入日志成功后返回ACK确认给主库,主库收到至少一个从库的确认就认为写操作完成
