高性能MySQL第三版-第一章(笔记)

高性能MySQL第三版-第一章

[提前声明]
大数据代码案例地址: https://github.com/Mydreamandreality/sparkResearch


MySQL逻辑架构

高性能MySQL第三版-第一章(笔记)_第1张图片

  1. 第一层:连接处理,授权认证,安全等
  2. 第二层:MySQL核心服务,查询解析,分析,优化,缓存,内置函数,视图(跨存储引擎的功能)等都在这一层
  3. 第三层:存储引擎,存储引擎负责MySQL中数据的存储和提取,存储引擎不会解析SQL,不同存储引擎之间也不会相互通信,只是响应上层服务器请求

连接管理与安全性

  1. 每个客户端连接都会在服务器进程中拥有一个线程
  2. 客户端连接MySQL服务器时,会进行基于用户名,原始主机信息和密码进行认证,或者SSL认证,连接后对进行特定查询的鉴权

原文注:MySQL5.5提供新API 支持线程池插件 复用池中少量的线程来服务大量的连接

优化与执行

  1. MySQL会解析查询,并创建内部数据结构,并进行优化,(重写查询,表读取顺序,选择索引)客户端也可以通过特殊关键字提示优化器(hint),影响决策过程,也可以查询优化过程(explain)
  2. 对于SELECT语句,解析查询之前会先检查查询缓存(query cache)命中则直接返回缓存中的结果集

并发控制

此处的并发控制指的是服务器与存储引擎两个层面的控制

场景:一张表,一条数据

  1. 同时写入

    1. 产生后果:数据损坏,两条数据交叉的附在表中
    2. 解决:操作数据时对数据上锁
    3. 影响:任意一个时刻,只有一个进程可以修改这条数据,不支持并发处理
  2. 同时读:无任何影响,因为读不修改数据,但此时我在读取该数据,你在删除该数据

    1. 产生后果:不确定,读取可能会错误退出

解决以上问题的方法:并发控制:

  1. 共享锁(读锁)
  2. 排它锁(写锁)

锁的概念:

  1. 读锁是共享的,互相不阻塞,多客户可以在同一时刻同时读取同一资源,互不干扰
  2. 写锁是排它的,一个写锁会阻塞其他的写锁和读锁,这是出于安全策略的考虑,这样才能确保一定时间内,只有一个用户能执行写入,并防止其他用户读取正在写入的同一资源

注:在Mysql中,每时每刻都发生锁定,当某个用户在修改一部分数据时,MySQL会通过锁定防止其他用户读取同一数据,大多数时候,MySQL锁的内部管理都是透明的

锁粒度

提高共享资源并发性的方式就是让锁定对象更优选择性,尽量只锁定需要修改的数据,而不是所有资源,任何时候,给定的资源中,锁定的数据量越少,系统的并发程度越高

注:加锁也需要消耗资源,获得锁,检查锁状态,释放等,都会增加系统开销,如果系统花费大量的时间来管理锁,而不是存取数据,那么系统数据可能会受到影响

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

MySQL提供多种选择,不同的存储引擎都可以实现自己的所策略和锁粒度

MySQL中两个重要的锁策略:

  1. 表锁

    1. 表锁是开销最小的策略,它会锁定整张表,当用户操作时,需要先获得写锁,这回阻塞其他用户对表的所有读写操作
    2. 写锁的优先级比读锁更高
  2. 行级锁

    1. 行级锁可以最大程度的支持并发处理,它只会锁定当前操作的这一条数据,同事也会带来最大的锁开销

注:锁只在存储引擎层实现,MySQL服务器层没有实现,并且完全不了解存储引擎中锁实现

事务

注:这些是数据库的通用基础,如果了解,建议直接略过

事务是一组原子性的SQL查询,独立的工作单元

如果能成功的执行工作单元内的全部语句,那么就执行,否则的话,如果有任何一条语句因为崩溃或者其它问题无法执行,那么工作单元内的所有语句都不会执行

简单来说,要么全部执行成功,要么全部执行失败

事务ACID
A:atomicity 原子性
C:consistency 一致性
I:isolation 隔离性
D:durability 持久性

  1. 原子性:

    1. 事务被视为一个不可分割的最小工作单元,事务中的所有操作,要么全部成功执行,要么全部失败回滚
  2. 一致性:

    1. 数据库从一个一致性的状态转换到另外一个一致性的状态
  3. 隔离性:

    1. 通常来说,一个事务所做的修改在最终提交之前,其它事务是不可见的,(后续有隔离级别详细介绍)
  4. 持久性:

    1. 事务提交后,修改会永久保存到数据库中

隔离级别

在SQL的标准中定义了四种隔离级别,每一种级别都规定了一个事务中所做的修改,哪些在事务内和事务间是可见的,哪些是不可见的,较低级别的隔离通常可以执行更高的并发,系统的开销也更低

注:每种存储引擎实现的隔离级别不一定相同

核心就是不同的锁粒度,配合锁粒度来理解

  1. READ UNCOMMITTED (未提交读)

    1. 在Read UnCommitTed级别, 事务中的修改,即使没有提交,对其他事务也都是可见的,其它事务可以读取未提交的数据,这就叫脏读,这个级别会导致很多的问题,而且性能也没有比其他的好太多,所以实际应用中一般很少用
  2. READ COMMITED(提交读/不可重复读)

    1. 一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的,但是会导致幻读,比如事务A删除数据1,但是此时没有提交,事务B查询数据1,然后要修改数据1,此时事务A删除数据,事务B修改数据发现报错了,造成幻读现象
  3. REPEATABLE READ(可重复读)(MySQL默认级别)

    1. 该级别保证了同一个事务中多次读取同样的记录的结果是一只的,但是理论上讲,可重复读隔离级别还是无法解决另一个幻读问题,当前事务在读取某个范围内的记录,另一个事务在该范围内插入了新的记录,之前的事务再次读取该范围的记录时,会产生幻行
  4. SERIALIZABLE(可串行化)

    1. 最高的隔离级别,通过强制事务串行执行,会在读取的每一行数据上都加锁,可能导致大量的超时和锁争用问题,一般不会用这种级别,除非你一定要保证数据的一致性,并且可以接受没有并发的情况,才会考虑一下这个级别

高性能MySQL第三版-第一章(笔记)_第2张图片

死锁

死锁是指两个或者多个事务在同一资源上互相占用,请求锁定对方占用的资源,从而导致恶性循环的现象,当多个事务试图以不同的顺序锁定资源时,就可能会产生死锁

案例:

事务A:

update ... where id =1
update ... where id =2

事务B:

update ... where id =2
update ... where id =1

如果凑巧,两条事务都执行了第一条更新语句,同时锁定当前数据,接着两个事务都尝试去执行第二条语句,却发现被锁定,然后两个事务都等待对方释放锁,同时又持有对方需要的锁,陷入死循环,此时除非有外部因素介入才可能解除死锁

为了解决这种问题,数据库实现了各种死锁检测和死锁超时机制

解决方案:
当查询的时间达到锁等待超时的设定后放弃锁请求

InnDB处理死锁的方法是:将持有最少行级排它锁的事务进行回滚,就能避免死锁

注:死锁发生后,只有部分或者完全回滚其中一个事务,才能打破死锁,对于事务性的系统,这是无法避免的

事务日志

事务日志可以提交事务的效率,使用事务日志,在修改表的数据时,只需要修改内存拷贝,再把修改行为记录到持久在硬盘上的事务日志中(binlog),而不用每次豆浆修改的数据本身持久到磁盘,事务日志采用的是追加的方式,因此写入日志的操作是磁盘上的一小块区域内的顺序IO,不是随机IP需要在磁盘的多个地方移动磁头,所以采用事务日志的方式相对来说要快得多,事务日志持久之后,内存中被修改的数据在后台可以慢慢的刷回到磁盘,(预写式日志),修改数据需要写两次磁盘

如果数据的修改意见记录到日志并持久化,但数据本身还没有写回磁盘,这个时候系统崩溃了,存储引擎在重启时,能够自动恢复这部分修改的数据,具体恢复方式视存储引擎而定

你可能感兴趣的:(SQL优化,一文读懂系列)