第01章 MySQL架构与历史

MySQL最重要的特性是它的存储引擎架构,它将查询处理与其他的系统任务和数据存储,提取相分离.

1 MySQL逻辑架构

最上层的是客户端:主要负责链接处理,授权认证,安全等

中间一层是MySQL的核心,服务器:主要负责查询解析,分析优化,缓存以及所有的内置函数,所有跨存储引擎的功能都在这一层实现,例如:存储过程,触发器,视图等

最下一层是存储引擎:存储引擎负责MySQL中数据的存储和提取,可以使用不同的存储引擎,不同的存储引擎有各自的优势和劣势,不同的存储引擎之间不能通信,只相应上层服务器的请求.服务器通过API与存储引擎进行通信,这些接口屏蔽了不同存储引擎之间的差异,这些差异对上层的查询过程透明.

1.1 客户端

每个客户端链接都会在服务器进程中拥有一个线程,这个客户端的查询都只会在这个线程中执行.服务器会缓存线程,因此不需要为每客户端的查询创建或是销毁线程.

当客户端链接到MySQL服务器时,服务器会对其进行认证.认证基于用户名,原始主机信息和密码,如果使用了安全套接字ssl,的方式链接,还会进行X.509证书认证.当客户端链接成功,服务器会继续验证该客户端是否具有执行某个特定查询的权限.

1.2 优化与执行

MySQL会解析传,并创建内部数据机构-解析数,然后对齐进行各种优化,包括重写查询,决定标的读取顺序,以及选择合适的索引等.用户可以通过特殊的关键字提示优化器,影响他的优化结果.也可以请求优化器解释优化过程的每个因素,这样用户可以知道服务器如何进行决策.

优化器不关心使用的是什么存储引擎,但是存储引擎对优化查询是由印象的,优化器会请求存储引擎提供容量或是某个具体操作的开销信息,以及表数据的统计信息等.

执行sql时,会先检查缓存,如果能找到对应的查询,那么服务器就不必再次执行查询解析,优化和执行的整个过程,而是直接返回查询缓存中的结果集.

2 并发控制

2.1 读写锁

在处理并发读或是写时,使用两种类型的锁:共享锁和排它锁(读锁和写锁).

2.2 锁粒度

锁策略是在锁的开销和数据的安全性之间寻找平衡.一般数据库都在加锁的会后都是添加行锁.

MySQL存储引擎可以实现自己的锁策略和锁粒度.

表锁:表锁是MySQL中最基本的策略,是开销最小的策略,会锁住整张表.写锁比读锁具有更高的有小鸡,因此写锁请求可能会被插入到读锁队列前面.

行级锁:行级锁可以最大成都的迟迟并发处理,也带来了更大的锁开销.行级锁只在存储引擎实现,MySQL服务器层没有实现行级锁.

3 事务

事务就是一组原子性的sql查询,或是一个独立的工作单元.如果数据库引擎能够成功的对数据库应用该组查询的全部语句,那么就执行该组查询.如果其中有任何一条语句因为崩溃或其他原因无法执行,那么所有的语句都不会执行.

MySQL中,实在存储引擎中实现事务.

3.1 ACID

ACID表示:

  1. 原子性atomicity:一个事物必须被视为一个不可分割的最小单元,整个事务中所有的操作要么全部提交成功,要么全部失败回滚,罪域一个事务来说,不可能只执行其中的一部分操作
  2. 一致性consistency:数据库总是从一个一致性的状态转换到另一个一致性的状态
  3. 隔离性isolation:通常,一个事务所作的修改在最终提交以前,对其他食物是不可见的.但并不总是如此,而不同的可见程度称为隔离级别
  4. 持久性durability:一旦事务提交,则所作的修改就会永久保存到数据库中.即使系统崩溃,修改的数据也不会丢失,持久性是一个有点模糊的概念,因为实际上持久性也分不同的级别.

事务的ACID特性可以保证数据的不会出错,但是要实现这一天非常难.一个兼容ACID的数据库,需要做很多复杂但肯恩用户并没有察觉到的工作,才能保证ACID的实现

一个实现了ACID的数据库,需要更强的cpu处理能力,更大的内存和更多的磁盘空间.

3.2 隔离级别

sql标准重定义了四种隔离界别:

  1. 未提交读read uncommitted:事务中的修改,即使没有提交,对其他事务也是可见的,事务可以读取未提交的数据,称为脏读 dirty read,这个级别会导致很多问题,并且性能上并不比其他级别好太多.因此很少用
  2. 提交读read committed,不可重复读:大多数数据库默认的隔离界别,一个事务开始时,只能看到已经提交的任务所作的修改.解决了脏读的问题.但是一个事务中执行相同的两次查询,可能得到不同的结果,因为在第一次和第二次查询之间,别的事务修改,并完成修改某项数据.
  3. 可重复读repeatable read:可重复读的解决了不可重复读.但是不能避免幻读,即某个事务修改了某一范围内的全部记录,而另一事务又在该范围内插入了新的记录.那么之前的事务在修改完这一范围的数据以后,再读取,就会出现幻行,通俗的说,就是明明都修改了,但是再次读取会发现有几条没有修改
  4. 可串行化serializable:是最高的隔离级别,强制事务串行执行.避免了前面说的幻读实际中很少用到这个隔离级别

MySQL通过:SET SESSION TRANSACTION ISOLATION LEVEL read committed;修改隔离级别

3.3 死锁

死锁值得是两个或是多个事务在统一资源上相互争用,并请求锁定对方占用的资源,从而导致双方都得不到所需资源的现象.

为了解决这个为题,数据库系统实现了各种死锁检测和死锁超时的基址,越复杂 的存储引擎,越能检测到死锁的循环依赖,并立即返回一个错误.InnoDB目前处理死锁的方法是,将持有最少行级排它锁的事务进行回滚.

3.4 事务日志

事务日志可以帮助提高事务效率,使用事务日志,存储引擎在修改数据的时候,只需要修改其内存拷贝,再把修改行为记录吃就在硬盘上的事务日志中,而不用每次豆浆修改的数据本身持久到磁盘.

事务日志采用的是追加的方式,因此写日志的操作是磁盘上一小块内存区域的顺序IO.事务日志持久化以后,内存中被修改的数据可在后台慢慢刷回到磁盘.这种方式称为预写式日志,也就是说修改数据需要写两次磁盘.

3.5 MySQL事务

MySQL中有两个存储引擎提供事务:Innodb和NDB Cluster.

MySQL中事务的特点有:

3.5.1 自动提交

自动提交:MySQL中默认自动提交模式,也就是说,每个查询都会被当做一个事务执行提交操作.可以通过设置autocommit来启用或是禁用自动提交模式:查询:SHOW VARIABLES LIKE 'AUTOCOMMIT';,设置:SET AUTOCOMMIT=1;(1开启,0关闭),对非事务存储引擎的表,没哟影响.

当关闭的时候,所有的查询都是在一个事务中,直到显示的执行COMMIT提交或是ROLLLBACK回滚.

3.5.2 在事务中混合使用存储引擎

MySQL的事务是由下层存储引擎实现.所以在同一个事务中,使用多种存储引擎是不可靠的.

如果在事务中混合使用了事务型和非事务性表,正常提交时没有问题,当时当需要回滚时,非事务型的表上的数据无法回滚.

3.5.3 隐式和显式锁定

Innodb采用的是两阶段锁定协议,在事务的执行过程中,随时都可以执行锁定,锁只有在执行COMMIT或是ROLLBACK时才会释放,并且同一时刻释放.这种锁定是隐式的,自动进行的.

InnoDB也可以进行显示锁定,在语句后面加上LOCK IN SHARE MOD或是FOR UPDATE进行读锁或是写锁

MySQL在服务器层面实现了LOCK TABLESUNLOCK TABLES语句.

4 多版本并发控制

多本版本并发控制MVCC可以认为是行级锁的一个变种,它在很多情况下避免了加锁操作,因此开销更低.

MVCC通过保存数据在某个点的快照来实现的.也就是说,不管需要执行多长时间,每个事务看到的数据都是一致的.根据事务开始的时间不同,每个事务对同一张表,同一时刻看到的数据可能是不同的.

不同的存储引擎的MVCC实现是不同的,典型的由乐观并发控制和悲观并发控制.

Innodb的MVCC是通过在每行记录后面保存两个隐藏的列来实现.这两个列,一个保存了行的创建时间,一个保存了行的过期时间.这个时间指的是系统版本号,每个开始一个新事务,系统版本号都会自动递增.事务开始时刻的系统版本号回座位事务的版本号,用来和查询到的每行记录的版本号比较.

例如,SELECT操作:Innodb只查找版本早于当前事务版本的数据行,这样可以确保事务读取的行,要么在事务开始前已经存在,要么是事务自身插入或者修改过的.行的删除时间要么是未定义的,要么大于当前事务的版本号.这样可以确保事务读取道德行,在事务之前未被删除.符合上述条件的记录,才会被作为结果返回

INSERT:为每一行保存当前系统版本号作为行的创建时间

DELETE:每一行保存当前系统版本号作为删除时间

UPDATE:保存当前系统版本号作为行的创建时间,同事保存当前系统版本号作为之前数据的删除时间

保存这两个额外的系统版本号,使得大多数读操作都可以不用加锁.(但是同一行记录,会由多条记录,是不同时间的快照),这使得读数据操作很简单,性能很好,并且只能读取到符合标准的行.不足之处就是需要额外的粗出空间.

MVCC值能在REPEATABLE READ和READ COMMITTED两个隔离级别下工作.

5 MySQL的存储引擎

5.1 信息

使用SHOW TABLE STATUS LIKE '表名' \G; (\G不使用表格的形式展示信息)

其中每个字段的信息如下:

name:表名

engine:存储引擎类型

version:存储引擎的版本

row_format:行格式,MySQL中可选dynamic标识行长度是可变的,一般包含可变长度的字段,fixed的行长度是固定的,compressed只在压缩表中存在

rows:表中的行数,对于innodb该值是估计值

avg_row_length:平均每行包含的字节数

data_length:表的数据大小,字节为单位

max_data_length:表的最大容量,该值和存储引擎有关

index_length:索引的大小,字节位单位

data_free:对myisam标识已分配但没有使用的空间

auto_increment:下一个auto_increment值

create_time:表的创建时间

update_time:表的最后修改时间

check_time:使用check table命令或是myisamchk工具最后一次检查表的时间

collation:表的字符集和字符排序规则

checksum:表的实时校验和

create_options:创建表时指定的其他选项

comment:包含一些其他的额外信息,不同存储引擎不同,innodb表示表的剩余空间信息

5.2 innodb存储引擎

innodb是MySQL默认的事务性引擎,也是使用最广泛的存储引擎.

被设计用来处理大量的短期事务,短期事务大部分都是正常提交的.

Innodb的数据存储在表空间中,表空间是由innodb管理的一个黑盒子,有一些列的数据文件组成.每个biao的数据和索引放在单独的文件中.

Innodb采用MVCC支持高并发,实现了四个标准的隔离界别.其默认级别是可重复读REPEATABLE READ.并通过间隙锁防止幻读的出现.间隙锁使得innodb不仅仅锁定查询设计的行,还会多索引中的间隙进行锁定,防止幻影行的插入.(间隙的意思可以理解为在btree中的next指针)

innodb表是基于聚簇索引建立的.聚簇索引对主键查询由很高的性能,而二级索引(就是非主键索引)都必须包含主键,所以如果主键列很大的话,其他的索引也会很大.因此如果表上的索引较多的话,主键应该尽量的小.

5.3 myisam存储引擎

myisam提供了全文索引,压缩,空间函数GIS等,但是不支持事务和行级锁.并且崩溃后无法安全恢复.

myisam会将表存储在两个文件中:数据文件和索引文件,分别是.MYD.MYI.myisam可以包含动态或者金泰行.

myisam的特性:

加锁与并发:myisam对整张表加锁

修复:执行表的修复可能造成数据的修复,并且修复操作非常的慢.

索引:对于BLOG和TEXT等长字段,可以基于其前500个字符建立索引

延迟更新索引键:指定了DELAY_KEY_WRITE后,每次修改执行完成后,不会立即将修改的索引数据写入磁盘,而是写到内存中的缓冲区

当创建完表后不会修改,这种表适合采用myisam压缩表,压缩表需要使用myisampack对myisam表进行压缩,且不能够修改,但可以解压.压缩表极大的减少了磁盘占用,提高了查询性能.

6 引擎选择

除非需要的特性是innodb不具备的,否则使用innodb

选择不同的存储引擎,可能需要考虑:

  1. 事务:innodb支持事务
  2. 备份:innodb支持在线热备份,
  3. 崩溃恢复
  4. 其他特性

某些情形下:

  1. 日志性应用:对插入速度有要求,因此myisam,archive比较适合,因为 他们开销第,并且chaussure速度快.当需要对这些数据进行处理的时候,可以先将数据复制,然后在备份上进行操作,这样可以避免对主库的影响,
  2. 只读或是大部分只读:建议innodb
  3. 订单处理:innodb
  4. 电子公告牌和论坛:读写压力大,并且需要数据一致性

7 转换表的引擎

musql创建表的时候,如果不指定engine,那么默认使用innodb存储引擎.

要修改表的存储引擎有三种方式.

7.1 ALTER TABLE

将表从一个存储引擎修改为另一个存储引擎最简单的办法是使用ALTER TABLE语句:

ALTER TABLE account ENGINE=MyISAM;

MySQL会按行,将数据从表复制到一张新的表中,进行大量的IO操作,并且会在原表上加锁.

并且不同存储引擎转换以后,外键可能会消失.

7.2 导入和导出

为了更好的控制转换的过程,可以使用MySQLdump工具,将数据导出到文件,然后修改文件中的CREATE TABLE的存储引擎选项,同时要修改表名(同一数据库中,表不能重名).另外,MySQLdump工具会在CREATE TABLE语句之前加上DROP TABLE,删除原表.

例如:

创建表的和数据库的语句位

DROP DATABASE IF EXISTS employ;
CREATE DATABASE employ;
USE employ;
CREATE TABLE account
(
    id int PRIMARY KEY AUTO_INCREMENT,
    name varchar(10)
) engine=myisam;

INSERT employ.account (name)VALUES('xiaoming'),('xiaohong'),('xiaozhang');

然后使用MySQLdump工具:

MySQLdump -uroot -p employ

默认会输出在终端,因此都会用重定向的形式输出到文件.

这种方式的缺点在于,只能导出整个数据库,不能导出某张表

7.3 创建与查询

总和了第一种和第二种方式.

使用CREATE TABLE tb_name LIKE old_tb的形式创建一张与原表结构相同的旧表,然后使用ALTER TABLE语句修改存储引擎,然后INSERT tb_name SELECT * FROM old_tb插入全部数据.

猜你喜欢

转载自www.cnblogs.com/perfy576/p/9155014.html