近日准备面试,复习了一些MySQL的知识,理清了一些概念,现在记录一下。
存储引擎
MySQL支持好几种存储引擎,最常用的是InnoDB。它现在是MySQL的默认引擎,支持事务,能用行级锁(就是只锁定你要修改的那一行数据,而不是整张表),还支持外键约束。
还有一个叫MyISAM的引擎,它在以前很流行。它不支持事务,只能锁定整张表,所以在很多人同时操作数据时效率不高。但它读取数据很快,适合那种主要是查询、很少修改的数据。
此外还有Memory引擎(数据存在内存里,超级快但电脑关机数据就没了)、Archive引擎(可以把数据压缩得很小,适合存储很多历史数据)和Blackhole引擎(数据写进去就不见了,听起来没用但在某些特殊场景下有作用)。
选择哪种引擎要看你的需求:需要事务安全就用InnoDB,需要快速读取且很少修改就用MyISAM,需要临时存储就用Memory。
简单来说:
InnoDB:MySQL 5.5后的默认存储引擎,支持事务、行级锁、外键约束,采用MVCC(多版本并发控制)来支持高并发,提供崩溃恢复和数据安全。
MyISAM:MySQL 5.5之前的默认引擎,不支持事务和外键,使用表级锁,适合读密集型应用,如网站统计数据。
Memory:数据存储在内存中,速度快但不持久,适合临时表和缓存。
Archive:适合存储大量历史数据,支持高压缩比和行级锁,但只支持SELECT和INSERT操作。
Blackhole:写入的数据会被丢弃,常用于主从复制中的中继。
MVCC
这个概念本来有点困惑,我用文档编辑类比就明白了:
如果办公室只有一份纸质文档,那么一次只能有一个人编辑它。但如果使用腾讯文档,多个人可以同时查看和编辑,这就类似MVCC的工作方式。
在InnoDB中,每行数据都有隐藏的版本信息。当你要修改数据时,不会直接覆盖原来的数据,而是创建一个新版本。读取数据时,你只能看到在你开始操作前已确认提交的数据版本。
这种机制的好处是,读取数据的人不会被修改数据的人阻塞,反过来同理。这大大提高了数据库的并发处理能力,让更多用户能够同时操作数据库而不会互相干扰。
事务隔离级别
MySQL提供了四种隔离级别:
- 读未提交(Read Uncommitted):最低级别,你能看到别人还没确认的修改。就像是看到别人正在输入的消息,但对方可能还会删掉重写。
- 读已提交(Read Committed):你只能看到已经确认的修改。在同一个事务中,你可能会看到数据发生了变化,因为别人的事务完成了。这就像是你在读一篇文章,刷新后发现内容更新了。
- 可重复读(Repeatable Read):InnoDB的默认级别。在整个事务过程中,你看到的数据不会因为别人的修改而变化。这就像是你在看一篇文章时,即使作者更新了内容,你看到的还是你开始阅读时的版本,直到你刷新页面。
- 串行化(Serializable):最高级别,通过强制事务排队执行来避免所有并发问题。这就像是一个单行道,安全性最高但效率最低。
InnoDB通过MVCC机制实现这些隔离级别。在读已提交级别,每次查询都会创建一个新的数据快照;而在可重复读级别,整个事务期间都使用同一个快照,这就保证了数据视图的一致性。
日志
主要有两种日志:redo log和bin log。
redo log(重做日志)这个日志空间固定,写满后会循环覆盖,主要用于崩溃恢复。
举个例子:假设你正在修改数据,突然停电了。当MySQL重启时,它会检查redo log,找出哪些修改还没来得及写入磁盘,然后重新执行这些修改,确保数据不丢失。
bin log(二进制日志)则像是一本详细的日记,记录了所有修改数据的SQL语句。它是追加写入的,不会覆盖旧数据,主要用于数据备份和主从复制。
如果这两种日志要记录一年的数据:
redo log由于空间固定且循环写入,不可能保存一年的所有记录,通常只能保存最近几小时到几天的操作。
bin log可以通过生成多个文件来保存整年的记录。这些文件会按时间或大小自动分割,可以设置保留策略(如保留30天),超期自动删除或归档。
慢SQL优化
慢SQL一般是指执行时间超过某个阈值(通常是10秒)的查询语句,但是也不一定,要看具体业务。
优化慢SQL的方法有很多:
索引优化:这是最基本也最有效的方法。给经常查询的字段、排序字段和连接字段创建索引,就像是给书加上目录,可以快速定位到需要的数据。但是索引也会占用空间并影响写入性能,所以不能滥用。
SQL语句重写:避免使用SELECT *,只查询需要的字段;避免使用OR、IN、NOT IN等可能导致全表扫描的操作;合理使用子查询和连接。
表结构优化:选择合适的字段类型和长度(比如存储性别用CHAR(1)就够了,不需要VARCHAR(255));适当进行表分区或分表,把大表拆成小表处理。
查询流程优化:先过滤,再关联,减少数据处理量;减少结果集大小,减少网络传输;批量操作代替单条操作。
工具方面,EXPLAIN命令是分析SQL执行计划的指令,它能告诉你SQL语句是如何执行的,是否使用了索引,扫描了多少行等信息。
索引
MySQL主要使用B+树索引。B+树是一种多路平衡树,它的非叶子节点只存储键值信息,不存储数据;所有叶子节点通过链表相连,形成有序表。这种结构特别适合磁盘存储,因为每个节点的大小通常等同于一个磁盘页,这样可以最大化I/O效率。
索引分为两种主要类型:
聚集索引(主键索引):决定了表中数据的物理存储顺序。每个InnoDB表都必须有一个聚集索引。它的叶子节点存储完整的数据行。通常是主键索引,如果没有定义主键,InnoDB会选择第一个非空唯一索引,或者自己创建一个隐藏的主键。
非聚集索引(二级索引):不影响数据的物理存储。它的叶子节点存储的是主键值,而不是完整的数据行。这意味着通过二级索引查询通常需要两步:先找到主键值,再通过主键值查找完整数据行,这个过程叫"回表"。
如果一个索引包含了查询所需的所有字段,就不需要回表,这叫"覆盖索引",是非常高效的。
索引失效的情况:
- 在索引列上使用函数(如SUBSTRING, CONCAT)
- 字符串和数字比较导致的隐式转换
- 使用LIKE '%abc'(左模糊查询)
- 使用!=, <>, NOT IN等否定操作符
- 复合索引不符合最左前缀原则(如创建了(a,b,c)的索引,但查询条件只有b和c)
设计索引:
- 为查询条件、排序和连接的字段创建索引
- 选择性(唯一值比例)高的字段更适合建索引
- 复合索引中把选择性高的字段放前面
- 控制索引数量,避免过度索引
虽然现在理解了,但是还是很容易忘记,还是要多多复习。