数据库相关问题
如何设计一个关系型数据库(RDBMS)?
索引相关
为什么要使用索引?
什么样的信息能成为索引?
索引的数据结构?
密集索引和稀疏索引的区别?
如何定位并优化慢查询SQL?
联合索引的最左匹配原则的成因?
索引是建立的越多越好吗?
MyISAM和InnoDB关于锁方面的区别?
MySIAM的适用场景?
InnoDB的适用场景?
锁的分类?
数据库事务的四大特性?ACID
事务隔离级别以及各级别下的并发访问问题?
InnoDB可重复读隔离级别下如何避免幻读?
如何设计一个关系型数据库(RDBMS)?
- 存储(文件系统)(机械硬盘,SSD固态硬盘)
- 程序实例:存取文件系统中的数据
-
- 存储管理:数据的逻辑关系转化成物理的存储关系;尽可能的减少IO,不能逐行查找,一次性读取多行。(数据库使用块或者页存取)
- 缓存机制:优化执行效率;某行数据被访问,他周边的数据极有可能也被访问。(如LRU)
- SQL解析:SQL语句解析
- 日志管理:记录操作,用于主从同步和灾难恢复,binlog方式
- 权限划分:控制数据访问权限
- 容灾机制:处理异常情况,数据库挂了怎么恢复,恢复到什么程度
- 索引管理:提升查询数据的速度
- 锁管理: 让数据库支持并发
索引模块
常见问题
- 为什么要使用索引
-
- 快速查询数据,少量数据也可用全表扫描
- 什么样的信息能成为索引
-
- 主键,唯一键以及普通键等
- 索引的数据结构
-
- 二叉查找树:若插入数据的顺序如下图所示,会导致时间复杂度变成线性,对二叉查找树做旋转操作改造成平衡二叉树可以解决此问题
-
- 平衡二叉树:数据库数据块非常多,二叉树只有两个子节点,树的层数过深,每一层都需要执行一次IO,效率很低
- 红黑树
- B树: 关键字+指向孩子的指针(多少个孩子取决于数据块的容量以及数据库的相关配置),目的(每个节点尽可能多的存储信息,让树的高度尽可能减少IO次数) https://www.cnblogs.com/xqzt/p/4456746.html
-
- 根节点至少包含两个孩子
- 树种每个节点最多含有m(层数)个孩子(m>=2)
- 除根节点和叶节点外,其他每个节点至少有ceil(m/2)个孩子
- 所有叶子节点都位于同一层
- 假设每个非终端节点中包含n个关键字信息,其中:
-
- Ki(I=1…n),且关键字按顺序升序排序K(i-1)<Ki (关键字数值左边比右边小)
- 关键字的个数n必须满足:[ceil(m/2)-1] <= n <= m-1 (关键字个数比孩子节点数量少一个)
- 非叶子节点的指针:P[1],P[2]…,.P[M],其中P[1]指向关键字小于K[1]的子树,P[M]指向关键字大雨K[M-1]的子树,其他P[i]指向关键字属于(K[i-1],K[i]) 的子树。(叶子节点3和叶子节点5比节点8的数值小)
-
- B+树(MySQL索引实现):B树的变体
-
- 非叶子节点的子树指针与关键字个数相同(5,10,20)个数 = (P1,P2,P3)
- 非叶子节点的子树指针P[i],指向关键字值[K[i],K[i+1]]的子树 ,(关键字10叶子节点的值必须小于关键字20)
- 非叶子节点仅用来索引,数据都保存在叶子节点中(非叶子节点不存储数据,可以存储更多的关键字,也就意味着层树更矮)
- 所有叶子节点均有一个链指针指向下一个叶子节点(方便在叶子节点做数据范围统计)
- B树和B+树结论,B+树更适合做存储索引:https://www.cnblogs.com/diegodu/p/8463150.html
-
- B+树的磁盘读写代价更低(非叶子节点不存储数据,大小更小,关键字更多)
- B+树的查询效率更加稳定(数据都在叶子节点,每一次扫描必须通过相同层数,查询更加稳定)
- B+更有利于对数据库的扫描(范围查询使用链指针更加有效率)
- Hash结构
-
- 缺点:哈希运算之后的值是无序的
-
- 仅仅能满足“=”,“IN”,不能使用范围查询
- 无法被用来避免数据的排序操作
- 不能利用部分索引建查询
- 不能避免表扫描
- 遇到大量Hash值相等的情况后性能并不一定比B+索引高(hash冲突)
- BitMap 位图索引: 字段取值只有固定的几个值
-
- 数据库支持有限,Oracle支持
- 缺点
-
- 锁的粒度非常大,发生新增或者修改时锁定范围大,不适合高并发的联机处理系统场景
-
- 密集索引和稀疏索引的区别
-
- 密集索引文件中的每个搜素码值都对应一个索引值(一个表只能创建一个密集索引)
- 稀疏索引文件只为索引码的某些值建立索引项
- MySIAM都是稀疏索引
- InnoDB有且仅有一个密集索引
-
- 若一个主键被定义,该主键则作为密集索引
- 若没有主键被定义,该表的第一个唯一非空索引则作为密集索引
- 若不满足以上条件,innodb呢哦不回生成一个隐藏主键(密集索引6字节的列)
- 非主键索引存储相关键位和其对应的主键值,包含两次查找
衍生出来的问题,MySQL为例
- 如何定位并优化慢查询SQL
-
- 根据慢日志定位慢查询SQL
-
- show variables like '%quer%’;
- set global slow_query_log = on; 打开慢查询日志
- Set global long_query_time = 1; 查询大于1秒属于慢查询
- show status like '%slow_queries%’; 记录慢查询sql语句
- 使用explain等分析工具分析SQL
-
- explain select * from walle_admin.system_config where name = 'singleLogin';
-
- 关注type:
- 关注extra
- 修改SQL或者尽量让SQL走索引
-
- explain select * from walle_admin.system_config where name = 'singleLogin' force index (primary); 强制走某索引
- 联合索引的最左匹配原则的成因
-
- 索引是建立的越多越好吗
-
- 数据量小的表不需要建立索引,简历会增加额外的索引开销
- 数据变更需要维护索引,因此更多的索引意味着更多的维护成本
- 更多的索引意味着需要更多的空间
锁模块
- MyISAM和InnoDB关于锁方面的区别
-
- MyISAM默认表级锁,不支持行级锁
- InnoDB默认行级锁,也支持表级锁
- 自动提交:show variables like 'autocommit’; set autocommit = 0;# 关闭自动提交
- 手动添加共享锁:select * from user where id =1 lock in share mode;
- InnoDB在SQL没有用到索引时,用的是表级锁,用到索引时用的是行级锁
Mac mysql my.cnf 位置:https://blog.csdn.net/StillCity/article/details/88558039
- mysql --verbose --help | grep my.cnf mysql读取的位置
- /usr/local/mysql/support-files 默认my.cnf存储的位置
- MySIAM适用场景
-
- 频繁执行全表count语句
- 增删改的频率不高,查询频繁
- 没有事务
- InnoDB适用场景
-
- 数据增删改比较频繁
- 可靠性高,支持事务
- 数据库事务的四大特性 ACID
-
- 原子性(Atomic):所有操作要么全做,要么全不做
- 一致性(Consistency):数据库数据的含义应满足完整性约束(转账场景,总金额始终不变)
- 隔离性(Isolation) :多个事务并发执行时,一个事务的执行不影响其他事务的执行
- 持久性(Durability):DBMS的恢复性能,redolog
- 事务隔离级别以及各级别下的并发访问问题
-
- 事务并发访问引起的问题以及如何避免
-
- 更新丢失 - MySQL所有事务隔离级别在数据库层面上均可避免
- 脏读 - READ-COMMITED事务隔离级别以上可避免,只能读到其他事物已经提交的记录(Oracle默认隔离级别)
-
- 手动设置最低的事务隔离级别:set session transaction isolation level read uncommitted ;
- 不可重复读 - REPEATABLE-READ以上的事务隔离级别即可避免,多次读取同一事务时结果不一致。
-
- 查询数据库默认事务隔离级别:select @@tx_isolation;
- set session transaction isolation level repeatable read ;
- 幻读 -SERIALIZABLE 事务隔离级别即可避免,MySQL的REPEATABLE-READ也可避免
-
- Session1 查询3条记录(未提交事务)
- Session2 插入1条记录(未提交事务)
- Session1 更新全部记录+1,提示有4行收影响,产生了幻觉
- InnoDB可重复读隔离级别下如何避免幻读
-
- REPEATABLE-READ隔离级别可以避免幻读
- 表象 :基于伪MVCC机制的快照读(非阻塞读)
-
- 当前读: 数据上的共享锁或排他锁都是当前读 ,读取的是记录的最新版本。
-
- select …lock in share mode
- Select … for update
- update
-
- delete
- insert
- 快照读:不加锁的非阻塞读
-
- select
- 内在: next-key锁(行锁+gap锁)
-
- 行 锁
- Gap锁 :锁定记录相邻的一个范围,但不包括记录本身
-
- 对主键索引或者唯一索引会用Gap锁吗?
-
- where条件全部命中,不会用gap锁,只会加记录锁
-
- where条件部分命中或者全不命中,则会加Gap锁,例如更新id=9的数据,insert id=10的数据会被block住
- Gap锁会用在非唯一索引或者不走索引的当前读中