- 原子性(atomicity) 最小的工作单元
- 一致性(consistency) 只能由一种状态到另一种状态,中间没有其他状态
- 隔离性(isolation) 一个事务的修改,在提交前,对其他事物不可见
- 持久性 (durability) 事务提交后,修改永久有效
- Read Uncommitted (未提交读)
- Read Committed(读提交)
- Repeatable Read (可重复读) mysql 默认隔离级别
- Seralizable (可串行化)强制事物串行化
俩个或者多个事务在同一个资源上相互占用,并请求锁定对方占用的资源
- 超过获取锁的等待时间,自动放弃获取锁
- 持有最少资源行级排他锁的事务回滚
-
悲观锁
悲观锁认为被它保护的数据是极其不安全的,每时每刻都有可能动,一个事务拿到悲观锁后(可以理解为一个用户),其他任何事务都不能对该数据进行修改,只能等待锁被释放才可以执行。数据库中的行锁,表锁,读锁,写锁,以及syncronized实现的锁均为悲观锁。
- 实现: select for update
- 优点:列用数据库的锁机制来实现对数据变化的顺序执行,这是最有效的办法
- 缺点:如果一个事务对数据加悲观锁,那么其他事务不能对数据做除查询以外的任何操作,如果该事务执行很长,其他事务一直等待,会对系统吞吐造成影响
- 场景: 适合应用在写为居多的场景
-
乐观锁
乐观锁认为他拿到数据不会频繁变动,允许多个事务并发的操作数据
- 实现:乐观锁通常是通过在表中增加一个版本(version)或时间戳(timestamp)来实现
- 优点:乐观锁不再数据库加锁,每个事务都可以对数据进行操作,在更新的时候才进行校验,避免了悲观锁造成的系统吞吐下降
- 缺点:乐观锁为我们人为实现,仅仅适用于我们自己的业务,如果有外来事务插入,会造成错误
- 场景: 读为居多的场景
-
InnoDB 行锁
Innodb默认使用的是行锁,行锁是基于索引实现的,因此使用行锁的时候必须命中索引,否则将使用表锁
数据每次修改,1、 修改内存拷贝; 2、 操作添加到持久在磁盘上的事务日志, 故需要写俩次磁盘
- 索引大大减少服务器要扫描的数据量
- 索引可以帮助服务器避免排序和临时表
- 索引可以将随机 I/O 变为 顺序 I/O
- B-Tree 索引 -- 基于 B+ 树索引实现
- 支持查询
- 值是按顺序存储的
- 遵循最左前缀
- 支持全值匹配,匹配列前缀和范围匹配
- 只访问索引
- 限制查询
- 如果不是按照索引的最左列开始查找,则无法使用索引
- 不能跳过索引中的列
- 如果查询中有某个列的范围查询,则其右边所有列都无法使用索引优化查询
- 支持查询
- hash 索引 --- 基于哈希表实现 (memory 引擎)
- 存储的时候没有排序,所以不能按照范围查询使用
- 只有精准匹配索引所有列的查询才有效
- 空间数据索引(R-Tree)( MyISAM 引擎 )
- 全文索引 (只适用于 match against 操作)
- 聚簇索引:按照主键构造B+树,同时叶子节点存放的即为整张表的行记录数据
- 覆盖索引:即从辅助索引中就可以得到查询的记录,而不需要查询聚簇索引中的记录。
- 库表结构优化
- 数据类型的选取
- 更小的通常更好
- 简单就好
整数优于字符,日期使用内置日期类型,ip存储为整数
- 尽量避免 NULL
- 数据类型的选取
- 索引优化
- 高效索引策略
- 独立的列,索引不能是表达式的一部分、函数的参数
- 前缀索引和索引选择性
- 多列索引
- 选择合适的索引列顺序,当不考虑排序和分组的时候,将选择性最高的列放在前面
select count(distinct staff_id)/count() as staff_selective,
count(distict customer_id)/count() as customer_selective,
count(*)
from payment \G
########### 1 row #############
staff_selective: 0.0001
customer_selective: 0.0373
count(*): 16049customer_id 选择性更大,所以选择 (customer_id, staff_id) 而是 (staff_id, customer_id)
- 聚簇索引,InnoDB聚簇索引实际上是在同一结构中保存了B-Tree 索引和数据行
- 覆盖索引,一个索引包含全部需要查询的列
- 冗余和重复索引
- 未使用的索引,应该删除掉
- 高效索引策略
- 查询优化
查询的生命周期:从客户端,到服务器,服务器(解析器,预处理器,查询优化器),生成执行计划,查询执行引擎,并返回客户端
- 慢查询
- 是否向数据库请求了不需要的数据
- mysql 是否在扫描额外的记录
慢日志记录了每个查询的 1,响应时间 2,扫描行数 3, 返回行数
- 重构查询方式
- 复杂查询和简单查询取舍
- 切分查询
- 分解关联查询
-
InnoDB 特性
- 支持事务,主要是为了在线事务处理(OLTP)设计的
- 行级锁,支持外键,非锁定读
- 支持多版本的并发控制 (Mvcc 版本控制)获得高并发特性
- 提供了插入缓冲、二次写、自适应哈希索引、预读等高性能和高可用的功能
- 适用场景:需要事务的场景,更新数据需要使用行级锁,大数据量读写,大型互联网应用
-
MyISAM 特性
- 不支持事务,主要为在线分析(OLAP)的应用而设计
- 表级锁
- 支持全文索引
- 它的缓冲只缓冲索引文件,不缓冲数据文件
- 适用场景:不需要事务的场景,插入、更新少,读取频繁,频繁的统计计算
lock | latch | |
---|---|---|
对象 | 事务 | 线程 |
保护 | 数据库内容 | 内存数据结构 |
持续时间 | 整个事务过程 | 临界资源 |
模式 | 表锁、行锁、意向锁 | 读写锁、互斥量 |
死锁 | 通过 waits-for、graph、time out等机制进行死锁检测 | 无死锁检测与处理机制 |
存在于 | lock manager的hash表中 | 每个数据结构的对象中 |
- 锁的粒度
- 表级锁
- 页级锁
- 行级锁
- 行级锁
- 共享锁 S Lock, select lock in share mode
- 排他锁 X Lock, select for update
为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB存储引擎支持一种额外的锁方式,就称为意向锁,即为表级别锁
- 表级锁
- 意向共享锁:事务想要获取一张表中某几行的共享锁
- 意向排它锁:事务想要获取一张表中某几行的拍他锁
-
一致性非锁定读:InnoDB 通过多版本控制(MVCC)读取当前时间数据库中行的数据。读的是快照,不需要等 X 锁的结束。极大提高并发性。默认读取方式
-
一致性锁定读:用户需要显示的对数据库读写加锁,以保证数据逻辑的一致性。下面是俩中一致性锁定读操作
- select for update
- select lock in share mode
-
锁的算法
- Record Lock: 单个行记录上的锁
- Gap Lock: 间隙锁,锁定一个范围,不包括记录本身
- Next-Key Lock: Gap Lock + Record Lock,
-
锁带来的问题
- 脏读:在不同的事务中,当前事务可以读到另一个事务未提交的数据。一般发生在(read uncommitted)
- 不可重复读:也称幻读。发生在(read committed) 级别下。 一个事务内多次对一块数据集读,在这个事务还没结束前,另外一个事务对该数据集做了 DML 操作,导致俩次读的数据不一致。mysql 一般通过 Next-key lock 算法避免不可重复读
- 丢失更新