前言
学习一门语言到一定程度要做小项目demo的时候,数据库就变成我们无路可绕的点,那么数据库的架构或者说数据库内部究竟有什么,下面是我总结的一些有关数据库的知识点。
(增删查改这些基础的点相信你已经了解了,下面这些是一些进阶内容)
数据库的基础架构图,下面是我百度的图:
从图的标记不难看出,索引管理和锁管理是数据库比较重要的部分,接下来我们也将围绕着这两个方面展开。
索引
接触多了增删查改的我们看到这一概念都会想问,为什么要用索引?
对于储存庞大数据量的数据库,我们肯定是想要快速查询信息,进一步地去想,如何避免每次查询都要全表查询,提高效率性能呢?
那么,什么样的信息能成为索引?
答案是:主键、唯一键以及普通键。
再往底层一点想,索引的数据结构是这样的,下面我们就深究索引的数据结构来谈。
索引的数据结构大概有以下几种:
- 建立二叉查找树进行二分查找(正常的时间复杂度为O(logn));
- 建立B-Tree结构进行查找(正常的时间复杂度为O(logn));
- 建立B±Tree结构进行查找;
- 建立Hash结构进行查找。
二叉查找树一般学数据结构都会涉及到所以这里我们不详细赘述,只谈谈二叉查找树容易出现的问题:
在取节点的时候容易出现树变成一条链的情况这种情况下的时间复杂度就会变成O(n)效率大幅下降。
B-Tree
B-Tree的定义:
- 根节点至少包括两个孩子;
- 树中每个节点最多含有m个孩子(m>=2);
- 除根节点和叶节点外,其他每个节点至少有ceil(m/2)个孩子;
- 所有叶子节点都位于同一层。(叶子高度一样)
(中间的节点是因为不够位置画所以不讨论)
假设每个非终端结点中包含n个关键字信息,其中:
- 关键字是按照升序排列的;
- 关键字的个数满足比最高孩子数-1;
- 对于非叶结点指针,最小的那个关键字域比起父结点的关键字域都小,最大的那个关键字域比起父结点的关键字域都大,其余都处于父结点关键字域之间。
B±Tree
B+Tree与B-Tree不同在于
- 非叶子节点的子树指针与关键字个数相同;
- 非叶子节点的子树指针P[i],指向关键字值(K[i],K[i+1])的子树即子树中的关键字域位于其父结点和父结点右边结点所形成的域之间;
- 非叶子节点仅用来索引,数据都保存在叶子节点中;
- 所有叶子节点均有一个链指针指向下一个叶子节点。
B+Tree的优势:
- B+树的磁盘读写代价比B–Tree更低;
- B+树的查询效率更加稳定;
- B+树更有利于对数据库的扫描。
Hash索引
Hash索引的有点很明显就是能快速查到数据,最快可达到O(1),但其缺点也十分明显:
- 仅能满足 = 、IN,不能使用范围查询;
- 无法被用来避免数据的排序操作;
- 不能利用部分索引键查询;
- 不能避免表扫描;
- 遇到大量Hash值相等的情况后性能并不一定就会比B树索引高。
进阶问题
密集索引和稀疏索引的区别
答:密集索引文件中的每个搜索码值都对应一个索引值,稀疏索引文件只为索引码的某些值建立索引项。
InnoDB是什么?其索引是如何定义的?
答:InnoDB是一种MySQL数据库引擎(数据和索引是一起存放的)。
1、若一个主键被定义,该主键则作为密集索引;
2、若没有主键被定义,该表的第一个唯一非空索引则作为密集索引;
3、若不满足以上条件,innodb内部会生成一个隐藏主键(密集索引);
4、非主键索引存储相关键位和其对应的主键值,包含两次查找(一次是次级索引自身然后再查找主键索引)。
如何定位并优化慢查询sql?
答:根据慢日志定位慢查询sql->使用explain等工具分析sql->修改sql或尽量让sql走索引。(此题为开放题,答案不唯一)
此思路下的部分步骤参考:
- show variables like ‘’;查询系统变量
- show status like ‘%slow_queries%‘;查找慢查询数量
- set global slow_query_log = on;开启慢查询日志
- set global long_query_time = 1;修改查询时间
- 在sql前面加上关键字explain
附带:使用explain后的部分结果字段属性含义:
- type中index和all属于全表查询
- extra中Using filesort表示MySQL会对结果使用一个外部索引排序。位置可能是在内存或磁盘
- Using temporary表示MySQL在对查询结果排序是用临时表。常出现在order by和group by 中
索引的最左匹配原则:MySQL会一直向右匹配直到遇到范围查询(<、>、and、between、like)就停止匹配
锁
二话不说先上图
行级锁:只针对当前操作行进行加锁。
表级锁:针对当前操作表进行加锁。
问题:MyISAM与Innodb关于锁方面的区别是什么?
答:MyISAM默认是表级锁不支持行级锁,Innodb默认是行级锁(用索引的时候)也支持表级锁(不用索引的时候)。
MyISAM适用的场景:
- 频繁执行全表count语句;
- 对数据进行增删改的频率不高,查询非常频繁;
- 没有事务。
Innodb适用的场景:
- 数据增删改查都相当频繁;
- 可靠性要求比较高,要求支持事务。
事务
数据库事务的四大特性
ACID:原子性、一致性、隔离性、持久性
事务并发访问引起的问题以及如何避免:
- 更新丢失——MySQL所有事务隔离级别在数据库层面均可避免(未提交读);
- 脏读——READ-COMMITTED事务隔离级别以上可避免(已提交读);
- 不可重复读——REPEATABLE-READ事务隔离级别以上可避免(可重复读);
- 幻读——SERIALIZABLE事务隔离级别可避免(串行化)。
当前读:获取数据的最新版本(select…lock in share mode,select …for update,update,delete,insert)
快照读:不加锁的非阻塞读(select)
问题:RC、RR级别下Innodb的非阻塞读如何实现?
答:1、数据行里的DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID字段;
2、undo日志记录操作前的老数据;
3、read view(RR级别下记录其他当前活跃的事务,RC级别下记录当前活跃的事务)。
Gap锁:间隙锁,对索引前后的间隙上锁,对索引自身不上锁,用于非唯一索引或不走索引的当前读中。
问题:对主键索引或者唯一索引会加Gap锁吗?
答:如果where条件全部命中,则不会用Gap锁,只会加记录锁;如果where条件部分命中或全不命中,则会加Gap锁。
问题:Innodb可重复读隔离级别下如何避免幻读?
答:引入next-key 锁,阻止特定的新纪录插入。