数据库事务
程序执行单元。
作用
- 提供数据库操作从异常中恢复到正常状态的方法,保证异常情况下数据一致性
- 多个应用或者多个线程访问数据库隔离。
特点
- ACID
数据库锁
并发下保证稳定性数据一致性。引擎有关。
数据一致性问题:
- 脏读
- 不可重复读
- 幻读
对应解决:
事务隔离机制。
- 读未提交
- 读提交
- 可重复读
- 串行化
表级别锁(myISM)
意向锁(Intention Locks)
意向锁是一种表级锁,用来指示接下来的一个事务将要获取的是什么类型的锁(共享还是独占)
行级别锁(InnoDB)
mysql默认innoDB。支持事务,支持行级别锁。
共享锁(s)
SELECT * FROM category WHERE category_no = 2 lock in SHARE mode; //共享锁
独占锁(x)
SELECT * FROM category WHERE category_no = 2 for UPDATE; //独占锁
UPDATE category set category_name = '动漫' WHERE category_no = 2; //独占锁
记录锁(record Locks)
间隙锁
隙锁是一种记录行与记录行之间存在空隙或在第一行记录之前或最后一行记录之后产生的锁。间隙锁可能占据的单行,多行或者是空记录。
MYSQL锁
- MySQL会对不存在的记录加gap锁,加gap锁的目的是防止幻读。同时在事务1对某条不存在的记录加锁的过程中,禁止插入其他新记录,所以MySql中对不存的记录加锁相当于此表不能插入任何记录,非常危险,在实际的业务中一定要注意。
- 对于普通索引加锁,事务会对数据加next-key锁(即记录锁加上gap锁),因为考虑到B+树索引的有序性,满足条件的项一定是连续存放的,加gap锁防止幻读,必须要保证一事务内连续两次读出都是一样,所以上面的插入必定失败,不在范围的数据插入才会成功
- 对唯一索引的记进行读取,其他事务可以向表插入新的记录,不能更新已加锁的记录,可以更新其他未加锁的记录,说明此时对表中已存在的记录只加排他锁。
- 对主键加锁读只会对该记录加排他锁,不会影响其他事务对记录的插入和更新。
- 无索引条件下加锁读数据时,会导致全表加上索引,其他事务全部阻塞,数据库基本会处于不可用状态。
索引
作用
加快查询
原理
- 为什么树不是hash
加速查找速度的数据结构,常见的有两类:
(1)哈希,例如HashMap,查询/插入/修改/删除的平均时间复杂度都是O(1);
(2)树,例如平衡二叉搜索树,查询/插入/修改/删除的平均时间复杂度都是O(lg(n));
select * from t where name=”sh”;
确实是哈希索引更快,因为每次都只查询一条记录。但是排序查询的SQL需求:分组:group by。排序:order by。比较:<、>。哈希型的索引,时间复杂度会退化为O(n),而树型的“有序”特性,依然能够保持O(log(n)) 的高效。 - 为什么是B+
二叉树
image.png - 当数据量大的时候,树的高度会比较高,数据量大的时候,查询会比较慢;
- 每个节点只存储一个记录,可能导致一次查询有很多次磁盘IO
B树
image.png - 不再是二叉搜索,而是m叉搜索;
- 叶子节点,非叶子节点,都存储数据;
- 中序遍历,可以获得所有节点;
B树被作为实现索引的数据结构被创造出来,是因为它能够完美的利用“局部性原理”。
局部性原理的逻辑是这样的:
(1)内存读写块,磁盘读写慢,而且慢很多;
(2)磁盘预读:磁盘读写并不是按需读取,而是按页预读,一次会读一页的数据,每次加载更多的数据,如果未来要读取的数据就在这一页(4k)中,可以避免未来的磁盘IO,提高效率;
(3)局部性原理:软件设计要尽量遵循“数据读取集中”与“使用到一个数据,大概率会使用其附近的数据”,这样磁盘预读能充分提高磁盘IO;
为啥用B树
(1)由于是m分叉的,高度能够大大降低;
(2)每个节点可以存储j个记录,如果将节点大小设置为页大小,例如4K,能够充分的利用预读的特性,极大减少磁盘IO;
b+树
image.png
(1)范围查找,定位min与max之后,中间叶子节点,就是结果集,不用中序回溯
(2)叶子节点存储实际记录行,记录行相对比较紧密的存储,适合大数据量磁盘存储;非叶子节点存储记录的PK,用于查询加速,适合内存存储;
(3)非叶子节点,不存储实际记录,而只存储记录的KEY的话,那么在相同内存的情况下,B+树能够存储更多索引;
总结 - 数据库索引用于加速查询
- 虽然哈希索引是O(1),树索引是O(log(n)),但SQL有很多“有序”需求,故数据库使用树型索引
- InnoDB不支持哈希索引
- 数据预读的思路是:磁盘读写并不是按需读取,而是按页预读,一次会读一页的数据,每次加载更多的数据,以便未来减少磁盘IO
- 局部性原理:软件设计要尽量遵循“数据读取集中”与“使用到一个数据,大概率会使用其附近的数据”,这样磁盘预读能充分提高磁盘IO
数据库的索引最常用B+树:
(1)很适合磁盘存储,能够充分利用局部性原理,磁盘预读;
(2)很低的树高度,能够存储大量数据;
(3)索引本身占用的内存很小;
(4)能够很好的支持单点查询,范围查询,有序性查询;
网友评论