0. 概述
我们的数据库一般都会并发执行多个事务,多个事务可能会并发的对相同的一批数据进行增删改查操作,可能
就会导致我们说的脏写、脏读、不可重复读、幻读这些问题。
这些问题的本质都是数据库的多事务并发问题,为了解决多事务并发问题,数据库设计了事务隔离机制、锁机
制、MVCC多版本并发控制隔离机制,用一整套机制来解决多事务并发问题。接下来,我们会深入讲解这些机
制,让大家彻底理解数据库内部的执行原理。
1. 事务处理
-
ACID:DBMS保证事务的ACID性质:
- Atomicity(原子性):要么完全执行,要么完全没有执行
- Consistency(一致性):从一个正确状态转换到另一个正确状态
- Isolation(隔离性):每个事务与其它并发事务互不影响
- Durability(持久性):Transaction commit后,结果持久有效,crash也不消失
-
Read uncommitted data (读脏数据) (写读):在T2 commit之前,T1读了T2已经修改了的数据
-
Unrepeatable reads(不可重复读) (读写):在T2 commit之前,T1写了T2已经读的数据;如果T2再次读同一个数据,那么将发现不同的值
-
Overwrite uncommitted data (更新丢失) (写写):在T2 commit之前,T1重写了T2已经修改了的数据
-
韩顺平版本:
-
隔离级别:
2. 数据仓库
-
数据仓库:少量的数据分析操作;每个操作访问大量的数据;分析操作以读为主
-
事务处理:大量的并发transactions;每个transaction访问很少的数据;读写
3. 数据库索引
索引是帮助MySQL高效获取数据的排好序的数据结构
索引的数据结构:二叉树、红黑树、B树、哈希表…
3.1 B+树
Mysql的底层实现就是B+树,只存储索引,每个叶子节点是排序好的,便于区间查询;Mysql默认每个节点的大小为16kb;
加入索引后,其实查询主要的开销还是在IO(从磁盘加载子树节点到RAM),高一点的mysql版本会直接将整个B+树初始化的时候就加入RAM,这样只需要最开始的一次IO,即可。
4. 存储引擎(面试重点)
mysql有多种存储引擎,但是常用的主要是这两种,分别为myisam和innodb,这两种数据结构都是用的b+树
B+树的非叶子节点不存储数据,只有叶子节点才存储数据
而B树的非叶子和叶子节点都会存储数据,会导致非叶子节点存储的索引值会更少,树的高度相对会比B+树高,平均的I/O效率会比较低所以使用B+树作为索引的数据结构,再加上B+树的叶子节点之间会有指针相连,也方便进行范围查找
4.1. MyISAM(非聚集索引)
-
不支持事务,但是操作是有原子性的
-
不支持外键,支持表锁,每次操作的时候都是锁住整张表
-
update会有表锁,所以并发量小,因为会进行阻塞。所以如果执行大量的SELECT,MyISAM是更好的选择
-
采用非聚集索引,索引文件的数据域存储指向数据文件的指针。辅索引与主索引基本一致,但是辅索引不用保证唯一
-
MyISAM的索引和数据是分开的,并且索引是有压缩的,内存使用率就对应提高了不少。能加载更多索引
-
主键索引和辅助索引
MyISAM存储引擎在使用索引查询数据时,
会先根据索引查找到数据地址,再根据地址查询到具体的数据
。并且主键索引和辅助索引没有太多区别。两个表都是差不多,查找的思路也都是根据索引找到数据地址,在通过数据地址找到数据
4.2. InnoDB(聚集索引)
与MyISAM相比,InnoDB的最大特色就是支持了ACID兼容的事务(Transaction)功能。
-
支持外键
-
支持行锁,采用MVCC来支持高并发,有可能死锁
-
对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引
-
InnoDB用于事务处理,具有ACID事务支持等特性。如果在应用中执行大量insert和update操作,可选择。
-
不支持全文搜索
-
主键索引和辅助索引
InnoDB中主键索引的叶子节点的数据区域存储的是
数据记录
,辅助索引存储的是主键值
。
主键索引采用聚集索引(索引的数据域存储数据文件本身),辅索引的数据域存储主键的值;因此从辅索引查找数据,需要先通过辅索引找到主键值,再访问主键索引;
(面试题)为什么建议InnoDB表必须建主键,并且推荐使用整型的自增主键?
最好使用自增主键,防止插入数据时,为维持B+树结构,文件的大调整。
Innodb中的主键索引和实际数据时绑定在一起的,也就是说Innodb的一个表一定要有主键索引,如果一个表没有手动建立主键索引,Innodb会查看有没有唯一索引,如果有则选用唯一索引作为主键索引,如果连唯一索引也没有,则会默认建立一个隐藏的主键索引(用户不可见)。(用户没有指定的话会自己找生产一个隐藏列Row_id来充当默认主键)
另外**,Innodb的主键索引要比MyISAM的主键索引查询效率要高(少一次磁盘IO),并且比辅助索引也要高很多**。
所以,我们在使用Innodb作为存储引擎时,我们最好︰
- 手动建立主键索引
- 尽量利用主键索引查询
自增ID可以保证每次插入时B+索引是从右边扩展的,可以避免B+树和频繁合并和分裂(对比使用UUID)
(面试题)为什么非主键索弓|结构叶子节点存储的是主键值? (一致性和节省存储空间)
4.3 总结(重点)
MyISAM:
- 优点:查询数据相对较快,适合大量的select,可以全文索引。
- 缺点:不支持事务,不支持外键,并发量较小,不适合大量update
InnoDB:
- 优点:支持事务,支持外键,并发量较大,适合大量update
- 缺点:查询数据相对较快,不适合大量的select
聚集索引和非聚集索引:
- 聚集索引(聚簇索引):表中的数据都会有一个主键,即使不创建主键,系统也会帮你创建一个隐式的主键。这是因为innodb是把数据存放在B+树中的,而B+树的键值就是主键,在B+树的叶子节点中,存储了表中所有的数据。
这种以主键作为B+树索引的键值而构建的B+树索引,我们称之为聚集索引。在B+树中,叶子节点存储整条记录的数据,这样的索引为聚集索引。
- 非聚集索引(非聚簇索引):
以主键以外的列值作为键值构建的B+树索引,我们称之为非聚集索引
。叶子节点不存储表中的数据,而是存储该列对应的主键,想要查找数据我们还需要根据主键再去聚集索引中进行查找,这个再根据聚集索引查找数据的过程,我们称为回表。
使用index(索引)
-
Tree based:有序,支持点查询和范围查询
-
Hash based:无序,只支持点查询
5.联合索引
在平时开发中,我们最常见的是聚集索引,但在我们需要多条件查询的时候,就不得不建立联合索引,来提高我们的查询效率
- 联合索引:也称复合索引,就是建立在多个字段上的索引。联合索引的数据结构依然是 B+ Tree
- 一颗 B+ Tree 只能根据一个值来构建,所以联合索引使用
最左
的字段来构建 B+ Tree
5.1 最左前缀匹配原则(重要)
最左优先,以最左边的为起点任何 连续 的索引都能匹配上,但遇到范围查询 (>、<、between、like) 就会停止匹配。之所以会有 最左前缀匹配原则和联合索引的索引构建方式及存储结构 是有关系的
- 联合索引是使用多列索引的第一列(最左)构建的 B+ Tree
- 用上面 (A,B) 的例子就是使用 A 列构建的 B+ Tree ,当 A 列值相等时再以 B 列进行排序(相对有序)
具体见:https://blog.csdn.net/weixin_38192427/article/details/120244367
(面试题)java开发中为什么不建议连表查询
web架构水平扩展很方便,方式mysql水平扩展是很困难的
一:单表查询更有利于后续维护;
二:代码可复用性高;
三:效率问题
- a:数据量小的情况下,连表查询的效率还是可以的,但是如果连表比较多,数据量上去,查询是笛卡尔积方式,查询的数据量是成几何倍上升的,这种情况下连表查询也必然会建立索引,这样的话索引的建立方式就要进行设计,需要一些索引功底的,如果索引建立不合适,是有可能会拖垮数据库的。
- b: 相比较而言,单表查询+代码上组装,逻辑比较清楚,维护方便,构建索引也相对很简单了,用多访问几次数据库,多几行代码换取效率上的提升,也是很可行的。
四:缓存利用率高
比如不常变动的数据,缓存下来,每次查询的时候就没必要再去查了,直接拿取,进行下面操作就可以了。
解决方法:分成很多小表,将一个大的sql语句拆分成很多小的sql语句,多次查询,多次使用java代码调用sql,多几行代码换取效率上的提升,也是很可行的
索引也相对很简单了,用多访问几次数据库,多几行代码换取效率上的提升,也是很可行的。
四:缓存利用率高
比如不常变动的数据,缓存下来,每次查询的时候就没必要再去查了,直接拿取,进行下面操作就可以了。
解决方法:分成很多小表,将一个大的sql语句拆分成很多小的sql语句,多次查询,多次使用java代码调用sql,多几行代码换取效率上的提升,也是很可行的