• 【高性能Mysql 】读书笔记(一)


    第1章 Mysql架构与历史


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

    MySQL逻辑架构

    image-20200208231431188

    • 第一层: 大多数基于网络的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不支持事务

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

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

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

  • 相关阅读:
    8天学通MongoDB——第一天 基础入门
    Struts2属性驱动与模型驱动
    前端传递参数,由于控制器层类实现了struts2的ModelDriven而产生的一个异常
    struts2之ModelDriven的用法
    JavaScript Array reverse 方法:颠倒数组中元素的顺序
    ibatis传入list对象
    ibatis中使用List作为传入参数的使用方法及 CDATA使用
    javascript 正则表达式判断只能是中文、英文或者中文加英文
    zclip结合easyui实现复制datagrid每行特定单元格数据的功能
    【Nodejs】使用put方式向后端查询数据并在页面显示
  • 原文地址:https://www.cnblogs.com/kkzhilu/p/12859487.html
Copyright © 2020-2023  润新知