一、MySQL结构与历史

1、MySQL逻辑结构

整体逻辑结构如下

第一层,最上层的服务并不是MySQL所独有的,大多数基于网络的C/S的工具或者服务都有类似的架构,比如连接处理,授权认证,安全等等

第二层,大多数MySQL的核心服务功能都在这一层,包括查询解析、分析、优化、缓存以及所有的内置函数(例如,日期、时间、数学、和加密函数),所有跨存储引擎的功能都在这一层实现:存储过程、触发器、视图等。

第三层包含了存储引擎,负责MySQL中数据的存储和提取。服务器通过API与存储引擎通信。存储引擎不解析SQL,互相之间不能通信,仅仅是简单的影响服务端的请求。

连接管理与安全

每个客户端连接都会在服务器进程中拥有一个线程,这个连接的查询只会在这个单独的线程中执行,该线程只能轮流在某个CPU核心或CPU中进行。服务器会负责缓存线程,因此不需要为每个新建的连接创建或者销毁线程。

当客户端连接到MySQL服务器时,服务器还需要对其进行安全认证。认证基于用户名、主机信息、密码等。如果使用了SSL的方式连接,还可以使用X.509证书认证。

优化与执行

MySQL会解析查询,并创建了一个内部数据结构(解析树)。然后对其进行各种优化。这些优化包括了,查询语句的重写,读表的顺序,索引的选择等等。可以通过特殊的关键字提示(hint)优化器,影响他的决策过程。也可以请求优化器解释(explain)优化过程中的各个因素。 另外,用户也可以请求服务器给出优化过程的各种说明,以获知服务器的优化策略,为用户提供了参数基准,以便用户可以重写查询,架构和修改相关服务器配置,便于mysql更高效的运行。

优化器并是不关心表使用了哪种存储引擎,但是存储引擎对服务器优化查询的方式是有影响的。优化器需要知道存储引擎的一些特性:具体操作的性能和开销方面的信息,以及表内数据的统计信息。例如,存储引擎支持哪些索引类型,这对于查询是非常有用的。

在解析查询之前,要查询缓存,这个缓存只能保存查询信息以及结果数据。如果请求一个查询在缓存 中存在,就不需要解析,优化和执行查询了。直接返回缓存中所存放的这个查询的结果。

explain https://www.snowruin.com/?p=1665

2、并发控制

本章的目的是讨论MySQL在两个层面的并发控制:服务器层与存储引擎层。并发控制是一个内容庞大的话题,本次只是简要讨论MySQL如何让控制并发读写。

读写锁

eg: email box

在处理并发读或者写时,可以通过实现一个由两种类型的锁组成的锁系统,来解决问题。这两种类型的锁通常被称为共享锁和排他锁,也叫读锁和写锁。

锁粒度

一种提高共享资源并发性的方式就是让锁定对象更有选择性。尽量只锁定需要修改的部分数据,而不是所有资源。更理想的方式是,只对会修改的数据片进行精确的锁定。

加锁也需要消耗资源。锁的各种操作,包括获得锁、检查锁是否已经解除、释放锁等,都会增加系统的开销。

所谓的锁策略,就是在锁的开销和数据的安全性之间找到平衡,这种平衡会影响到性能

表锁

表锁是MySQL最基本的锁策略,并且是开销最小的策略。

详见mysql中lock tables与 unlock table

http://note.youdao.com/noteshare?id=bed98d71bc3967054f40bdf056473370&sub=BDD5AAC8A62A4094B76F6639986538F0

行锁

行锁可以最大程度地支持并发处理(同时也带来了最大的锁开销)。众所周知,在InnoDB和XtraDB,以及其他一些存储引擎中实现了行级锁。行锁只存在存储引擎层实现,而MySQL服务器层没有实现。

3、事务

行锁可以最大程度地支持并发处理(同时也带来了最大的锁开销)。众所周知,在InnoDB和XtraDB,以及其他一些存储引擎中实现了行级锁。行锁只存在存储引擎层实现,而MySQL服务器层没有实现。

事务就是一组原子性的SQL查询,或者说一个独立的工作单元。事务内的语句,要么全部执行成功,要么全部执行失败。

start transaction;

select ...

update ...

insert ...

commit

eg:银行扣钱

ACID 原子性 一致性 隔离性 持久性

原子性:一个事务必须被视为不可分割的最小工作单元。

一致性:数据库总是从一个一致性的状态转换成另外一个一致性的状态。即使update操作失败,账户也不会损失200美元。

隔离性:一个事务所做的修改在最终提交以前,对其他事务是不可见的。参考隔离级别

持久性:一旦事务提交,则其所做的修改就会持久保存到数据库中。此时及时系统崩溃,修改的数据也不会丢失。

事务的ACID特性可以确保银行不会弄丢你的钱。而在应用逻辑中,要实现这一点非常难,甚至可以说是不可能完成的任务。一个兼容ACID的数据库系统,需要做很多复杂但用户并没有觉察的工作,才能确保ACID的实现。

隔离级别

READ UNCOMMITTED(未提交读) 事务中的修改,即使没提交,对其他事务也是可见的。可以读取未提交的数据,称为脏读。

READ COMMITTED(提交读) 满足前面提到的隔离性的简单定义:一个事务开始时,只能看见已经提交事务所做的修改。换句话说,一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。成为不可重复读。因为两次执行同样的查询,可能会得到不一样的结果。

REPEATATBLE READ(可重复读)解决了脏读的问题,保证了在同一事务中多次读取同一个记录的结果是一致的。

但是解决不了幻读。幻读是指当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入新的记录,当之前的事务再次读取该范围的记录时,会产生幻行。

可重复读是MySQL的默认事务隔离级别

SWERIALIZABLE(可串行化) 最高隔离级别,通过强制事务串行执行,避免了前面说的幻读。简单来说就是在读取每一行的时候都加锁,所以可能导致大量的超时和锁竞争的问题。

死锁

死锁是指两个或者多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。

eg:

事务1

start transaction;

update user set phone='110' where user_id = 2;

update user set phone='119' where user_id = 3;

commit;

事务2

start transaction;

update user set address='jiang' where user_id = 3;

update user set address='qiang' where user_id = 2;

commit;

事务日志

使用事务日志,存储引擎在修改表的数据时只需要修改其内存拷贝,再把修改行为记录到持久在硬盘的事务日志中,而不是每次都将修改的数据本身持久化到磁盘。

https://www.cnblogs.com/f-ck-need-u/archive/2018/05/08/9010872.html

MySQL中的事务

MySQL提供了两种事务型的存储引擎,InnoDB 和 NDB Cluster 。另外还有一些第三方存储引擎也支持事务

自动提交 (AUTOCOMMIT)

MySQL默认采用自动提交模式,也就是说,如果不是显式地开始一个事务,则每个查询都被当做一个事务执行提交操作。

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

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

3、多版本并发控制

MVCC是行级锁的一个变种,但在很多情况下避免了加锁操作,因此开销更低,

MVCC的实现是通过保存数据在某个时间点的快照来实现的。

4、MySQL存储引擎

InnoDB vs MyISAM

https://www.cnblogs.com/y-rong/p/8110596.html

InnoDB是MySQL默认事务型引擎,也是最重要、使用最广泛的存储引擎。它设计用来处理大量的短期事务,短期事务大部分情况下是正常提交的,很少会被回滚。

InnoDB概览

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

InnoDB采用MVCC支持高并发,并且实现了四个标准的隔离级别

InnoDB表是基于聚簇索引建立的

除非需要用到某些InnoDB不具备的特性,并且没有其他办法可以替代,否则都应该优先选择InnoDB引擎

eg:如果要用全文索引,建议优先考虑InnoDB+Sphinx组合,而不是使用全文索引的MyISAM

MySQL引擎变更方法

1、ALTER TABLE alter table mytable engine = innodb

可以适用任何存储引擎。但有一个问题:需要执行很长时间。MySQL会按行将数据从原表复制到一张新的表,在复制期间可能会消耗系统所有的I/O能力,同时将原表上会加上读锁。所以在繁忙的表上执行要小心

2、导出与导入

mysqldump 将数据导出到文件,修改文件中create table语句中的存储引擎选项

3、创建与查询(create 和 select)

create table innodb_table like myisam_table;

alter table innodb_table engine=innodb;

insert into innodb_table select * from myisam_table;

数据量不大的话,这样做工作很好。如果数据量很大,则可以考虑分批处理

start transaction;

insert into innodb_table select * from myisam_table where id between x and y;

commit ;

猜你喜欢

转载自blog.csdn.net/u011028179/article/details/85129482