数据库

MySQL 引擎

InnoDB

  • InnoDB是一个事务型(A原子C一致I隔离D持久)的存储引擎,有行级锁定外键约束
  • InnoDB不支持FULLTEXT类型的索引。
  • InnoDB没有保存表的行数,当SELECT COUNT(*) FROM TABLE时需要扫描全表。
  • 支持自动增加列属性auto_increment。
  • 支持故障恢复。

MyISAM

  • MyISAM拥有较高的插入、查询速度,但不支持事务不支持外键约束
  • 设计之时就考虑到 数据库被查询的次数要远大于更新的次数。
  • ISAM(索引顺序访问方法)执行读取操作的速度很快,而且不占用大量的内存和存储资源。
  • 不支持主动恢复。

引擎对比

事务、外键支持

MyISAM不支持事务和外键,而InnoDB支持。

MyISAM是非事务安全型的,而InnoDB是事务安全型的,默认开启自动提交。

全文索引

MyISAM

支持(FULLTEXT类型的)全文索引

InnoDB

不支持(FULLTEXT类型的)全文索引

表锁差异

MyISAM

只支持表级锁,用户在操作myisam表时,select,update,delete,insert语句都会给表自动加锁,如果加锁以后的表满足insert并发的情况下,可以在表的尾部插入新的数据。

InnoDB

支持事务行级锁,是innodb的最大特色。行级锁大幅度提高了多用户并发操作的性能。但是InnoDB的行锁,只是在WHERE的主键是有效的,非主键的WHERE都会锁全表的。

存储结构

MyISAM

每个MyISAM在磁盘上存储成三个文件。第一个文件的名字以表的名字开始,扩展名指出文件类型。.frm文件存储表定义。数据文件的扩展名为.MYD (MYData)。索引文件的扩展名是.MYI (MYIndex)。

InnoDB

所有的表都保存在同一个数据文件中(也可能是多个文件,或者是独立的表空间文件),InnoDB表的大小只受限于操作系统文件的大小,一般为2GB。

事务隔离级别

Read Uncommitted(读取未提交内容)

在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)

Read Committed(读取提交内容)

这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。

Repeatable Read(可重读)

这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。

Serializable(可串行化)

这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

  • 脏读(Drity Read)
    • 某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。
  • 不可重复读(Non-repeatable read)
    • 在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。
  • 幻读(Phantom Read)
    • 在一个事务的两次查询中数据数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。

索引

为什么使用索引?

  • 加快数据检索速度。
  • 避免排序耗时。
  • 将随机I/O变为顺序I/O

为什么不全部使用索引?

  • 对表中内容进行修改的时候,索引也要动态维护
  • 索引会占据一定的空间

索引覆盖

如果一个索引包含所有需要查询的字段的值,称为覆盖索引。即只需扫描索引而无须回表

回表即通过索引找到了对应项的主键,再通过主键访问数据

最左前缀

MySQL中的索引可以以一定顺序引用多列,这种索引叫作联合索引

如User表的name和city加联合索引就是name - city

name=xx and city=xx; //命中索引

where name=xx; //命中索引

where city=xx; //未命中索引

冗余索引

根据最左前缀,重复命中的索引。name - city 和 name。

B树 / 平衡多路查找树

  • innoDB的主索引B+树叶子节点中包含的是数据辅助索引子节点中包含的是主键
  • innoDB引擎在查询辅助索引的时候会查询两次,首先通过辅助索引得到主键值,然后再查询主索引。
  • MyISAM的主索引B+树叶子节点中包含的是行号。MyISAM的辅助索引在结构上和主索引没有本质的区别。

为什么索引不使用红黑树实现?

如果用红黑树存储,增加或者减少数据时红黑树需要做旋转之类的操作来保持平衡,那么就需要把所有节点都加载到内存中,查找时也需要全部加载到内存,所以不适合。

B树与B+树的区别

  • B+树是在B树的基础上改造的,B+树的数据都在叶子节点上,同时,叶子节点之间还加了指针形成链表
  • B+树在数据库的索引中用得比较多,如果需要查询多条数据,B树需要做局部的中序遍历,可能要跨层访问。而B+树由于所有数据都在叶子结点,不用跨层,同时由于有链表结构,只需要找到首尾,通过链表就能把所有数据取出来了。
  • 这也是为什么没有在数据库中用Hash的原因,查找一个数Hash更快,但是查找多个数字的时候就没有B+树快

大表优化问题

垂直分区/列拆分

简化表结构/主键冗余

水平分区/行拆分

数据表结构不变/分表仅仅是解决了单一表数据过大的问题,但由于表的数据还是在同一台机器上,其实对于提升MySQL并发能力没有什么意义,所以水平拆分最好分库