本文是阅读 《高性能 MySQL 》一书所做的基本学习笔记。
表锁
表锁是 MySQL 中最基本的锁策略,开销最小。它会锁定整张表,一个用户在对表进行写操作时,需要先获得写锁,这会阻塞其他用户对该表的所有读写操作。只有没有写锁时。其他读取用户才能获得锁,读锁之间不是相互阻塞。
行级锁
它可以最大程度地支持并发处理,同时也带来了最大的锁开销。它只在存储引擎层实现。它仅对指定的记录进行加锁,这样其它进程还是可以对同一个表中的其它记录进行操作。
事务
事务是一组原子性的 SQL 查询。事务符合 ACID 概念。
- 原子性 atomicity
事务中所有操作要么全执行,要不全部不执行。 - 一致性 consistency
数据库保证从一个一致性状态转换到另一个一致性的状态。 - 隔离性 isolation
事务所做的修改在提交以前,对其他事务是不可见的。 - 持久性 durability
一旦事务提交,它所做的修改会永久保存到数据库中,它不会丢失。
隔离级别
- READ UNCOMMITTED 未提交读
事务的修改,即使没有提交,其他事务都是能看见的。也就是说,其他事务可以读取未提交的数据,这很不好,所以又称脏读 , 因为无法确保数据的真实可靠性和一致性。 - READ COMMITED 提交读
事务开始时,只能看见已经提交的事务所做的修改。即一个事务从开始直到提交之前,所做的任何提交对于其他事务都是不可见的。也叫 不可重复读,因为两次执行同样的查询,可能会得到不一样的结果。 - REPEATABLE READ 可重复读
MySQL 默认的事务隔离级别。它解决了脏读的问题。保证同一事务中多次读取同样的结果时一致的,但无法解决幻读问题。幻读:当某个事务在读取某个范围内的记录时,另一个事务在该范围内插入了新的记录,所以该事务再次读取本范围时,发现了不一样的行,称为幻行。Innode 通过 多版本并发控制(MVCC)解决了它. - SERIALIZABLE 可串行化
最高的隔离级别。强制事务串行执行。在非常需要确保数据的一致性而且可以接受没有并发的情况下,可以考虑这个级别。
事务的实现
事务的隔离性是通过锁实现的,而事务的原子性,一致性和持久性则是通过事务日志实现的。
事务日志又分为:redo log 和 undo log
redo :事务开启时,事务中的操作,都会写入到存储引擎的日志缓冲中,在事务提交之前,缓冲的日志提前刷新到磁盘上持久化,即“日志先行”。当事务提交后,数据文件才会刷新到磁盘。如果出现意外情况,那么可以根据 redo log 中的日志记录,将数据库恢复到前一个状态。未完成的事务,可以继续提交,也可以回滚。
undo log:主要为事务的回滚服务。事务除了记录 redo log,还会记录 undo log。undo log 记录了数据在每个操作前的状态。回滚就是根据它进行的。单个事务的回滚不会影响到其它事务。
redo log 保障的是事务的持久性和一致性,而undo log则保障了事务的原子性。
MVCC 多版本并发控制。不同的存储引擎 MVCC 的实现不同,典型有 乐观锁和悲观锁。InnoDB 是通过在每行记录后面保存两个隐藏的列来实现的。一个是行的创建时间,一个是行的过期时间,存储的不是实际时间,而是系统的版本号。每开始一个新事物,它会递增。具体如下操作:
select:
行的系统版本号小于或等于事务的系统版本号,确保事务读取的行,要么是在事务开始之前已经存在的,要么是事务自身修改的。还有行的删除版本号要么没有定义,要么大于事务版本号。
insert:
为每一行保存当前系统版本号
delete:
为删除的每一行保存当前系统号为删除标识
update:
为插入一行新纪录,保存当前系统版本号作为行版本号,保存当前系统号到原来的行作为删除标识。
死锁
多个事务在同一个资源上相互占用,并请求锁定对方占用的资源,导致恶性循环的现象。
索引的三个优点
- 索引大大减少了服务器需要扫描的数据量
- 索引可以帮助服务器避免排序和临时表
- 索引可以将随机 I/O 变为 顺序 I/O
索引三星系统:
- 索引将相关的记录放在一起获得一星
- 如果索引中的数据顺序和查找中的排序一致得二星
- 索引中的列包含了查询中需要的全部获得三星
高效的索引策略
- 独立的列:查询中的列如果不是独立的,MySQL 不会。独立的列指的是索引列不能是表达式的一部分,也不能是函数的参数。
- 前缀索引和索引选择性
- 通常可以索引开始的部分字符,可以大大节约索引空间,但也会降低索引的选择性
- 选择性:不重复的索引值和数据表的记录总数的比值,选择性越高则查询效率越高,因为选择性高的索引可以让 MySQL 在查找时过滤掉更多的行
- 选择合适的索引列顺序
- 聚簇索引:并不是一种单独的索引类型,而是一种数据存储方式
- 覆盖索引:如果一个索引包含(或者说覆盖)所有需要查询的字段的值,就称为覆盖索引