阅读《高性能mysql第三版》笔记(一)

前言:全文笔记都是阅读书籍记录的,请各位大佬多多指教,有不对的地方指点一番。谢谢!

1.MySQL的逻辑架构

mysql 三木运算结果 sanic mysql_mysql


第一层架构:连接MySQL的客户端,可以是Navicat,SQLyog,或者代码的JDBC连接等等。每一个SQL的执行都是一个线程的创建和销毁过程,但是在MYSQL5.5版本只有进行的优化,会有ThreadPool的概念,减少消耗。

第二层架构:MySQL的核心层,里面包括触发器,存储过程,视图,内置函数,缓存,解析和分析等等。

第三层架构:是存储引擎,(原文)负责mysql数据的存储和提取。存储引擎主要分为InnoDB和MyISAM,还有MEMORY、ARCHIVE等等其他的。存储引擎InnoDB会解析SQL的外键,而MYISAM不会。

2.并发控制

在并发情况下,我们读取的数据被修改了,这个时候读取的结果是不确定的。为了能控制这个问题的产生于是就有了读锁和写锁,也叫共享锁和排它锁。

读锁是共享的,不相互堵塞多个用户在同一时刻可以同时读取同一资源。
写锁是排他的,一个写锁会阻塞其他的写锁和读锁。

3.锁粒度

每种MySQL存储引擎都可以实现自己的锁策略和锁粒度。下面介绍两种重要的策略。

表锁:它锁定整张表,阻塞其他用户对表的读写操作。它是MySQL最基本的锁策略,也是开销最小的。尽管存储引擎能够管理锁策略,MySQL本身还是有其它实现表锁,例如ALTER TABLE之类的语句。
行级锁:可以最大程度的支持并发操作,也是最大的锁开销。行级锁只在存储引擎有实现,在服务层没有实现。

4.事务

4.1 特性

原子性:一个事务必须被视为一个不可分割的最小单元。
一致性:数据库总是从一个一致性的状态转到另一个一致性的状态。
隔离性:一个事务所做的修改在最终提交以前,对其他事务是不可见的。
持久性:一旦事务提交,数据是持久化保存在数据库中的。

4.2 隔离级别

(READ UNCOMMITTED)未提交读:在事务未提交的时候,对其他事务是可见的,产生脏读现象;

(READ COMMITTED)提交读(不可重复读):一个事务提交之前,只对自己可见,别人是不可见的。

(REPEATABLE READ)可重复读:提交读会产生幻读现象,指的是当某一个事务在读取某一个范围内的记录时,另一个事务又在该范围内插入新的记录,当之前事务再次读取数据时,会有幻行现象。InnoDB和XtraDB通过MVCC技术解决了幻读问题。

(SERIALIZABLE)串行化:强制事务串行化,避免幻读。只有在强一致性上,才会使用该隔离级别。

MYSQL可以通过执行命令: set transactional isolation level [隔离级别]

参考此文就能理解这四种隔离级别:https://baijiahao.baidu.com/s?id=1742126549941015304&wfr=spider&for=pc

4.3 隔离级别

死锁是指两个或者更多的事务在同一资源进行抢占,导致死锁问题。

原文例子(如下图):当两个事务,在同一时间对第一行数据进行修改,当尝试执行第二条语句是,会等待对方释放锁,会产生死锁问题,陷入死循环。

mysql 三木运算结果 sanic mysql_java_02


解决办法:(1)死锁检测和超时连接。(通常来说不太好)

(2)重新执行因死锁的事务。

4.4 事务日志

事务日志可以帮助事务提高事务效率。通过改变内存中的数据,然后修改记录行为持久化到硬盘的事务日志中,后台慢慢刷到磁盘中。

4.5 MySQL的事务

MySQL提供两种事务性的存储引擎,InnoDB和NDB Cluster。

查看语句为show variables like ‘AUTOCOMMIT’;

mysql 三木运算结果 sanic mysql_存储引擎_03


1或ON表示启动,0或OFF表示关闭。

MySQL默认启用自动提交模式,也就是说对于单个语句,MySQL是会被当作一个事务操作的。

set AUTOCOMMIT=1:开启自动提交。set AUTOCOMMIT=0:关闭自动提交。

还有一些命令,才执行之前强制执行COMMIT提交当前的活动事务。典型的就是DDL中。ALTER TABLE,LOCAL TANLE等语句。

可以通过 SET TRANSACTION ISOLATION LEVEL READ COMMITED 命令这是隔离级别,也可以设置当前会话的隔离级别:
mysql > SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITED;

5.多版本并行控制

MySQL的大多数事务型存储引擎实现的都不是简单的行级锁。基于提升并发性能的考虑,它们一般同时实现多版本并发控制,也就是MVCC。MVCC的实现,是通过保存数据在某个时间点的快照来实现的。。
MYSQL的实现是通过每一行记录后面保存两个隐藏的列来实现的。这两个列。一个保存行的创建时间,一个保存行的过期时间(或删除时间),当然不是存储实际的时间,而是系统版本号。下面看一下在repeatable read隔离级别下,MVCC具体是如何操作的。
select
    InnoDB会根据以下两个条件检查每行记录:
    a,InnoDB会查询版本早于当前事务版本的数据行,这样可以确保事务读取的行,要么是在事务开始已经存在的,要么是事务自身插入或者修改的。
    b,行的删除版本要么未定义,要么大于当前事务版本号,这样可以确保事务读取到的行,在事务开始之前未被删除。
insert
    InnoDB为新插入的每一行保存当前系统版本号作为行版本号。
delete
    InnoDB为删除的每一行保存当前系统版本号作为删除标志。
update
    InnoDB为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标志。

注意:MVCC只在可重复读和不可重复读(提交读)两个隔离级别下工作,其他两个隔离级别和MVCC不兼容;因为**读未提交级别**,每次都是读取最新的值,而**可序列化级别**是直接加锁操作。
read committed总是读取最新的数据行,而不是符合当前事务版本的数据行,而serializable则会对所有读取的行都加锁。

6.存储引擎

MySQL存储引擎,每创建一个表,都会在数据库的data目录下建立一个子文件,文件名称为 表名.frm
例如:sys_user表,存储目录在:/data/mysql/lemon_admin,lemon_admin 是数据库名称,表结构数据保存在sys_user.frm,因为以文件形式持久化保存表结构,所以在Unix操作平台需要注意大小写问题(Unix大小写是敏感的)。

MySQL如何查看表的基本信息:

show table status like 'sys_user';

执行结果:

mysql 三木运算结果 sanic mysql_mysql_04


字段解析:

Name:表名。

Engine:存储引擎。

Version:表的 .frm 文件的版本号。

Row_format:行的格式。可选值为:Dynamic(行长度可变)、Fixed(行长度固定)、Compressed(只在压缩表中存在)。

Rows:表中的行数。

Avg_row_length:平均每行包含的字节数。

Data_length:表的数据大小。

Max_data_length:表最大存储容量,该值和存储引擎有关。上图示例查询为0。

Index_length:索引大小

Data_free:已分配但没有使用的空间

Auto_increment:下一个自动递增的值

Create_time:创建时间

Update_time:修改时间

Check_time:使用ckeck table 命令检测表的时间

Collation:表的默认字符集和字符排序规则

Checksum:如果启用,保存整个表的实时校验和

Create_options:创建表时指定其他选项

Comment:该列包含了一些其他额外信息。对于InnoDB表,保存的时InnoDB表空间的剩余空间信息。如果是一个视图,则显示VIEW。

6.1 InnoDB概览

InnoDB的数据存储在表空间(tablespace)中,表空间是由InnoDB管理的黑盒子,由一系列的数据文件组成。

InnoDB采用MVCC支持高并发,并且实现了四个标准的隔离级别。其中默认的隔离级别是可重复读,并且通过间歇锁策略防止幻读的出现。间歇锁是的InnoDB不仅仅锁定查询涉及的行,还会对索引中的间歇进行锁定,以防止幻影行的插入。

InnoDB表是基于聚簇索引建立的,索引结构和MySQL的其他存储引擎有很大不同,聚簇索引对主键查询有很高的性能。不过它的二级索引中必须包含主键列,所以如果主键很大的话,其他的所有索引都很大。

6.2 MYISAM存储引擎

缺点:(1)不支持事务和行级锁
(2)系统崩溃无法安全恢复。
myisam是比较早数据库默认版本,缺点有点多,有时候性能又不足InnoDB,比如建立索引之后MYISAM就无法比拟InnoDB。(所以略过)