第1章 Mysql架构与历史


MYSQL最重要、最与众不同的特性是它的存储引擎架构,这种架构的设计将查询处理( Query Processing)及其他系统任务( Server Task)和数据的存储/提取相分离。这种处理和存储分离的设计可以在使用时根据性能、特性、以及其他需求来选择数据存储的方式。

MySQL逻辑架构

  • 第一层: 大多数基于网络的C/S的工具或服务都是类似的结构,比如连接处理 授权认证 安全
  • 第二层: 大多数MySQL 的核心服务功能都在这一层,包括查询解析、分析、优化、缓存以及所有的内置函数(日期、时间、数学和加密),所有跨存储引擎的功能都在这一层实现:存储过程、触发器、视图
  • 第三层: 存储引擎负责Mysql中数据的存储和提取。和GUN/Linux下的各种文件系统一样,每个存储引擎都有它的优势和劣势。存储引擎不会解析SQL(InnoDB除外,它会解析外键定义,Mysql服务器本身没有实现该功能)不同的存储引擎也不会相互通信,只是响应上层服务器的请求,服务器通过API与存储引擎进行通信,且这些接口屏蔽了不同存储引擎之间的差异

修正认知错误:读了高性能Mysql才认识到,对于任意一个成熟的版本,它都是由服务端层+核心功能+存储引擎三部分构成,且对于同一个版本而言,选择的存储引擎不同,导致Mysql的性能和特点也大大不同

注:

  • Mysql 主要分为Server层(Server服务层 + 核心功能层)和引擎层,Server层主要包括连接器、查询缓存、分析器、优化器、执行器,同时还有一个日志模块(binlog),这个日志模块所有执行引擎都可以共用

  • 引擎层是插件式的,目前主要包括,MyISAM,InnoDB(默认),Memory等

  • 查询语句的执行流程如下:

查询缓存(命中缓存) —》权限校验

查询缓存(未命中缓存)—》分析器—》优化器—》权限校验—》执行器—》引擎

  • 更新语句执行流程如下:分析器----》权限校验----》执行器—》引擎—redo log(prepare 状态—》binlog—》redo log(commit状态)

连接管理及安全性

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

Mysql服务在运行时即会创建好一个线程池,然后对接客户端请求,因此不需要为每一个新建的连接创建或者销毁线程

线程池的上限也决定了一个Mysql库难以承载高并发的需求

优化与执行

MYSQL会解析查询,并创建内部数据结构(解析树),然后对其进行各种优化,包括重写査询、决定表的读取顺序,以及选择合适的

素引等、同时用户可以通过特殊的关键字提示(hint)优化器,影响它的决策过程

这里想到了某天开发组长和一个组员争论的问题:

聚合索引a、b、c

在查询的时候不按照abc的顺序是否可以应用上索引,(explain select * from test where b = 1 and c = 1 and a = 1)

答案是肯定的,依然会通过索引查询,即是因为优化器的优化

并发控制

Mysql在解决并发场景下多个查询在同一时刻修改数据问题时,主要从服务层及存储引擎层进行控制

读写锁

和Java层面的读写锁类似,对于Mysql中共享锁及排他锁,即读写锁也是保证了读读之间共享,读写,写写间相互排斥

在实际的数据库系统中,每时每刻都在发生锁定,当某个用户在修改某一部分数据时MYSQL会通过锁定防止其他用户读取同一数据,

大多数时候, MYSQL锁的内部管理都是透明的

锁粒度

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

是,只对会修改的数据片进行精确的锁定。任何时候,在给定的资源上,锁定的数据量越少,则系统的并发程度越高,只要相互之

间不发生冲突即可。但于此同时,锁本身也是一种开销,如果为了减少锁定的数据量导致锁本身占用资源过多,也是得不偿失。

因此大多数商业数据库一般都是在表上施加行级锁(row - level lock),并以各种复杂的方式来实现,以便在锁比较多的情况下尽

可能提供更好的性能

而Mysql则提供了多种方案选择,每种存储引擎都可以实现自己的锁策略和锁粒度,主要有两种:

表锁:

故名意思即锁定整个表,需要注意的是写锁比读锁具有更高的优先级,因此一个写锁请求可以优先于读锁请求执行

另外,尽管各个存储引擎可以实现自己的锁机制,但是Mysql服务端会为诸如ALTER,TABLE之类的语句使用表锁,而忽略存储引擎

自己的策略

行级锁:

行级锁策略在Mysql服务端完全没有实现,都是借由存储引擎实现,如:InnoDB

事务

事务具有四个必要特性:

原子性(A):不可分割的最小单位

一致性(C):要么都成功要么都失败

隔离性(I):事务之间不可见

持久性(D):事务提交,永久生效

隔离级别

  • READ UNCIMMITTED(未提交读):造成脏读,实际很少使用
  • READ COMMITTED(提交读 / 不可重复读): 两次执行同样的查询,可能会得到不一样的结果
  • REPEATABLE READ(可重复读):依然会有幻读(Phantom Read) 的问题,进一步通过多版本并发控制(Multi version Concurrency Control,MVCC)解决,是MySQL的默认隔离级别
  • SERIALIZABLE(串行化):在读取的每一行上都加上锁,可能导致大量的超时和锁争用,实际很少使用

死锁

死锁的必要条件:

  • 互斥:某种资源一次只允许一个进程访问
  • 占有且等待 : 一个进程本身占有资源(一种或多种),同时还有资源未得到满足,正在等待其他进程释放该资源
  • 不可抢占:无法抢占其他已被占用的资源
  • 循环等待:存在一个进程链,使得每个进程都占有下一个进程所需的至少一种资源

为了解决这种问题,数据库系统实现了各种死锁检测和死锁超时机制。越复杂的系统,比如 INNODB存储引擎,越能检测到死锁的

循环依赖,并立即返回一个错误,且在同一个场景中由于存储引擎不同,A引擎可能产生死锁,B则不会

事务日志

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

事务日志采用的是追加的方式,写日志操作是磁盘上的顺序I/O,所以要快很多,事务日志持久以后,内存中被修改的数据可以在

后台慢慢刷回到磁盘,称之为预写式日志(Write-Ahead Logging),修改操作需要写两次磁盘

Mysql中的事务

Mysql提供了两种事务性的存储引擎:InnoDB 和 NDB Cluster

自动提交(AUTOCOMMIT)

Mysql默认采用自动提交(AUTOCOMMIT)的模式,如果不明确开始一个事务,则每个查询都被当做一个事务执行提交操作

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

Mysql服务器不管理事务,事务是由下层存储引擎实现的。混合使用事务型和非事务性的表不会有问题(例如 InnoDB 和 MyISAM),但是回滚时,非事务的表无法撤回

隐式和显示锁定

InnoDB 采用的是两阶段锁定协议(two-phase locking protocol),随时可执行锁定,在执行commit 后者rollback时会释放,这是隐式锁定

显示锁定(强烈不建议使用)

SELECT … LOCK IN SHARE MODE

SELECT … FOR UPDATE

多版本并发控制

多版本并发控制,即MVCC,该模块是基于提升并发性能的考虑,它是行级锁的一个变种,但是它在很多的情况避免了加锁的操

作,因此开销更低,虽然实现机制有所不同,但大都实现了非阻塞的读操作,写操作也只锁定必要的行

INNODB的MVCC,是通过在每行记录后面保存两个隐藏的列来实现的。这两个列,一个保存了行的创建时间,一个保存行的过期时间

(或删除时间)。当然存储的并不是实际的时间值,而是系统版本号( system version number)。每开始一个新的事务,系统版本号都

会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号进行比较。

我个人感觉MVCC的策略和Java8中的乐观读写锁- StampedLock 非常相似,通过乐观锁的思路,减少悲观锁的使用和阻塞的情况发生,StampedLock 是通过对比邮戳整数Stamp,而Mysql通过对比系统版本号来决定需不需要完全加锁

Mysql的存储引擎

Mysql的存储引擎多种多样,远远不是很多面试答案中题到的:MyISAM及 InnoDB两种,通过高性能Mysql书中对于各种存储引擎的

介绍,在选择存储引擎时候大概率可以毋庸置疑的选择InnoDB

不过新的问题来了,什么是存储引擎:根据较新的Mysql版本,存储引擎早已支持插件化了,即一个Mysql存储引擎是实现了Mysql存储引擎基本接口的程序,可以以插件的形式与Mysql数据库一同工作

也就是说,如果你能力足够强,你也可以完全自定义一个Mysql存储引擎

InnoDB概览

InnoDB采用mvcc来支持高并发,实现了四个标准的隔离级别,默认级别是REPEATABLE READ(可重复读),通过间隙锁(next-key

locking)策略防止幻读的出现。间隙锁使得InnoDB不仅仅锁定查询设计的行,还会对索引中的间隙进行锁定,防止幻影行的插入.

InnoDB是通过聚簇索引建立的,InnoDB的索引结构和其他存储引擎有很大的不同,聚簇索引对主键查询有很高的性能,但二级索

引必须包含主键列,如果主键列很大的话,其他的所有索引都会很大。因此弱表上的索引较多的话,主键应当尽可能的小。InnoDB

的存储格式是平台独立的,可以将数据和索引文件从Intel平台复制到PowerPC或者Sun SPARC.

InnoDB 内部做了很多优化,包括从磁盘读取数据时采用的可预测性预读,能够自动在内存中创建hash索引以加速读操作的自适应

哈希索引,以及能够加入检查入操邹的插入缓冲区(insert buffer)

Mysql的其他存储引擎不支持热备份,要获取一致性视图需要停止对所有表的写入。

MyISAM引擎

Mysql 5.1及以前的版本,MyISAM是默认的储存引擎。提供了大量的特性,包括全文索引 压缩 空间函数(GIS),但MyISAM不支持事务

和行级锁,而且有一个大的缺陷,崩溃后无法修复。

优势:存储数据支持压缩,占用较小

提醒:绝对不要混用存储引擎!!!

【高性能Mysql 】读书笔记(一)的更多相关文章

  1. 高性能MySQL --- 读书笔记(1) - 2016/8/2

    此书不但帮助MySQL初学者提高使用技巧,更为有经验的MySQL DBA指出了开发高性能MySQL应用的途径.全书包括14章,内容覆盖MySQL系统架构.设计应用技巧.SQL语句优化.服务器性能调优. ...

  2. 高性能MySQL --- 读书笔记(2) - 2016/8/2

    第1章 MySQL架构 MySQL架构与其他数据库服务器大不相同,这使它能够适应广泛的应用.MySQL足够灵活,能适应高要求架构.例如Web应用,同时还适用于嵌入式应用.数据仓库.内容索引和分发软件. ...

  3. 高性能mysql读书笔记(一):Schema与数据类型优化

    4.5 加快ALTER TABLE 操作的速度 原理: MySQL 的ALTER TABLE 操作的性能对大表来说是个大问题. MySQL 执行大部分修改表结构操作的方法是用新的结构创建一个空表,从旧 ...

  4. 【MySQL 读书笔记】当我们在执行该查询语句的时候我们在干什么

    看了非常多 MySQL 相关的书籍和文章,没有看到过如此优秀的专栏.所以未来一段时间我会梳理读完该专栏的所学所得. 当我们在执行该查询语句的时候我们在干什么 mysql> select * fr ...

  5. 【MySQL 读书笔记】SQL 刷脏页可能造成数据库抖动

    开始今天读书笔记之前我觉得需要回顾一下当我们在更新一条数据的时候做了什么. 因为 WAL 技术的存在,所以当我们执行一条更新语句的时候是先写日志,后写磁盘的.当我们在内存中写入了 redolog 之后 ...

  6. 【MySQL 读书笔记】普通索引和唯一索引应该怎么选择

    通常我们在做这个选择的时候,考虑得最多的应该是如果我们需要让 Database MySQL 来帮助我们从数据库层面过滤掉对应字段的重复数据我们会选择唯一索引,如果没有前者的需求,一般都会使用普通索引. ...

  7. 【MySQL 读书笔记】RR(REPEATABLE-READ)事务隔离详解

    这篇我觉得有点难度,我会更慢的更详细的分析一些 case . MySQL 的默认事务隔离级别和其他几个主流数据库隔离级别不同,他的事务隔离级别是 RR(REPEATABLE-READ) 其他的主流数据 ...

  8. 【MySQL 读书笔记】全局锁 | 表锁 | 行锁

    全局锁 全局锁是针对数据库实例的直接加锁,MySQL 提供了一个加全局锁的方法, Flush tables with read lock 可以使用锁将整个表的增删改操作都锁上其中包括 ddl 语句,只 ...

  9. 【MySQL 读书笔记】当我们在使用索引的时候我们在做什么

    我记得之前博客我也写过关于索引使用的文章,但是并不全面,这次尽量针对重点铺全面一点. 因为索引是数据引擎层的结构我们只针对最常见使用的 Innodb 使用的 B+Tree 搜索树结构进行介绍. 每一个 ...

  10. 《高性能MySQL》笔记——MySQL建表数据类型的选择

    前段时间看了<高性能MySQL>中的选择优化的数据类型,这里主要是做一下笔记. 首先数据选择有几个简单原则: 更小的通常更好.一般情况下,应该尽量使用可以正确存储数据的最小数据类型.例如只 ...

随机推荐

  1. 域名注册诈骗邮件We are an agency engaging in registering brand name and domain names

    最近收到了一封自称是某公司的邮件,说有人要注册我已经申请的域名,需要我回复确认,看邮件发件人是个人邮箱,通篇没有提到公司,也不是什么正规机构,大概率就是诈骗邮件了. 为了完全确认这封诈骗邮件,我登陆了 ...

  2. typedef 定义指针数组和数组指针及其使用。

    #include<stdio.h> typedef char arr[][]; typedef char *name[]; // 指针数组 typedef char (*lan)[]; / ...

  3. Java并发编程-Unsafe实现原理与Unsafe应用解析

    前言 Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别.不安全操作的方法,如直接访问系统内存资源.自主管理内存资源等,这些方法在提升Java运行效率.增强Java语言底层资源 ...

  4. F查询与Q查询、事务及其它

    一.F查询和Q查询 1.1 F查询 在上面所有的例子中,我们构造的过滤器都是将字段值与某个我们自己设定的常量做比较.如果是对两个字段的值做比较,那这时候就要用到F查询了. Django提供F()来做这 ...

  5. 关于idea的一些快捷键

    最近在用idea写代码,熟悉一些快捷键的使用能够让写代码的速度提高,以下快捷键是默认idea的快捷键,当然我们可以自己修改的: 自动补全代码快捷键:CTRL+alt+V 自动格式化代码:CTRL+al ...

  6. 使用 Nginx 部署静态页面

    Nginx 介绍 Nginx 是俄罗斯人编写的十分轻量级的 HTTP 服务器, Nginx,它的发音为「engine X」,是一个高性能的 HTTP 和反向代理服务器,同时也是一个 IMAP/ POP ...

  7. CodeForces 3 D.Least Cost Bracket Sequence【贪心+优先队列】

    Description 给出一个括号序列,中间有一些问号,将第i个问号换成左括号代价是a[i],换成右括号代价是b[i],问如果用最少的代价将这个括号序列变成一个合法的括号序列 Input 第一行一个 ...

  8. 洛谷 P6145 【[USACO20FEB]Timeline G】

    这道题难就难在建图吧,建图懂了之后,跑一遍最长路就好了(也就是关键路径,但是不会用拓补排序求qnq,wtcl). 怎么建图呢?先不管输入的S,看下面的输入,直接建有向边即可,权值为x.如果现在跑最长路 ...

  9. Django迁移命令无法生成mysql表

    数据库迁移问题:在执行python manage.py makemigrations迁移命令之后,正常输出并生成迁移文件,但执行python manage.py migrate之后显示,No migr ...

  10. 新技术新框架不断涌现,目前学习web前端开发都要掌握什么?

    web前端开发由网页制作演变而来,随着web2.0的发展,网页不再只是承载单一的文字和图片,各种丰富媒体让网页的内容更加生动,网页上软件化的交互形式为用户提供了更好的使用体验,这些都是基于前端技术实现 ...