文章目录
- 数据库的三范式是什么?
- drop、delete与truncate的区别
- 索引
- 索引是什么?
- 索引有哪些优缺点?
- MySQL有哪几种索引类型?
- 说一说索引的底层实现?为什么索引结构默认使用B+Tree,而不是B-Tree,Hash,二叉树,红黑树?
- 讲一讲MySQL的最左前缀原则?
- 了解索引下推吗?
- 创建索引时需要注意什么?
- 建索引的原则有哪些?
- 什么情况下不走索引(索引失效)?
- 事务
- 什么是数据库事务?
- 介绍一下事务具有的四个特征
- 事务的实现原理
- MySQL事务日志介绍下?
- 什么是MySQL的 binlog?
- 什么是 MVCC?
- MVCC实现原理?
三者都表示删除,但是三者有一些差别:
索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。
索引是一种数据结构。数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用B树及其变种B+树。更通俗的说,索引就相当于目录。为了方便查找书中的内容,通过对内容建立索引形成目录。而且索引是一个文件,它是要占据物理空间的。
MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度。比如我们在查字典的时候,前面都有检索的拼音和偏旁、笔画等,然后找到对应字典页码,这样然后就打开字典的页数就可以知道我们要搜索的某一个key的全部值的信息了。
优点:
缺点:
1、从存储结构上来划分: BTree索引(B-Tree或B+Tree索引),Hash索引,full-index全文索引,R-Tree索引(R树)。这里所描述的是索引存储时保存的形式,
2、从应用层次来分: 普通索引,唯一索引,复合索引。
3、根据中数据的物理顺序与键值的逻辑(索引)顺序关系: 聚集索引,非聚集索引。
Hash索引
基于哈希表实现,只有精确匹配索引所有列的查询才有效,对于每一行数据,存储引擎都会对所有的索引列计算一个哈希码(hash code),并且Hash索引将所有的哈希码存储在索引中,同时在索引表中保存指向每个数据行的指针。
B-Tree索引(MySQL使用B+Tree)
B-Tree能加快数据的访问速度,因为存储引擎不再需要进行全表扫描来获取数据,数据分布在各个节点之中。
B+Tree索引
是B-Tree的改进版本,同时也是数据库索引索引所采用的存储结构。数据都在叶子节点上,并且增加了顺序访问指针,每个叶子节点都指向相邻的叶子节点的地址。相比B-Tree来说,进行范围查找时只需要查找两个节点,进行遍历即可。而B-Tree需要获取所有节点,相比之下B+Tree效率更高。
B+tree性质:
n棵子tree的节点包含n个关键字,不用来保存数据而是保存数据的索引。
所有的叶子结点中包含了全部关键字的信息,及指向含这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。
所有的非终端结点可以看成是索引部分,结点中仅含其子树中的最大(或最小)关键字。
B+ 树中,数据对象的插入和删除仅在叶节点上进行。
B+树有2个头指针,一个是树的根节点,一个是最小关键码的叶节点。
为什么索引结构默认B+Tree,可以参考这篇文章:索引-底层实现原理
最左前缀原则就是最左优先,在创建多列索引时,要根据业务需求,where子句中使用最频繁的一列放在最左边。 mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
=和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式。
MySQL 5.6引入了索引下推优化。默认开启,使用SET optimizer_switch = ‘index_condition_pushdown=off’;可以将其关闭。
有了索引下推优化,可以在减少回表次数
在InnoDB中只针对二级索引有效
官方文档中给的例子和解释如下:
在 people_table中有一个二级索引(zipcode,lastname,address),查询是SELECT * FROM people WHERE zipcode=’95054′ AND lastname LIKE ‘%etrunia%’ AND address LIKE ‘%Main Street%’;
如果没有使用索引下推技术,则MySQL会通过zipcode=’95054’从存储引擎中查询对应的数据,返回到MySQL服务端,然后MySQL服务端基于lastname LIKE ‘%etrunia%’ and address LIKE ‘%Main Street%’来判断数据是否符合条件
如果使用了索引下推技术,则MYSQL首先会返回符合zipcode=’95054’的索引,然后根据lastname LIKE ‘%etrunia%’ and address LIKE ‘%Main Street%’来判断索引是否符合条件。如果符合条件,则根据该索引来定位对应的数据,如果不符合,则直接reject掉。
事务是一个不可分割的数据库操作序列,也是数据库并发控制的基本单位,其执行的结果必须使数据库从一种一致性状态变到另一种一致性状态。事务是逻辑上的一组操作,要么都执行,要么都不执行。
事务最经典也经常被拿出来说例子就是转账了。
假如小明要给小红转账1000元,这个转账会涉及到两个关键操作就是:将小明的余额减少1000元,将小红的余额增加1000元。万一在这两个操作之间突然出现错误比如银行系统崩溃,导致小明余额减少而小红的余额没有增加,这样就不对了。事务就是保证这两个关键操作要么都成功,要么都要失败。
事务就是一组原子性的操作,这些操作要么全部发生,要么全部不发生。事务把数据库从一种一致性状态转换成另一种一致性状态。
事务是基于重做日志文件(redo log)和回滚日志(undo log)实现的。
每提交一个事务必须先将该事务的所有日志写入到重做日志文件进行持久化,数据库就可以通过重做日志来保证事务的原子性和持久性。
每当有修改事务时,还会产生 undo log,如果需要回滚,则根据 undo log 的反向语句进行逻辑操作,比如 insert 一条记录就 delete 一条记录。undo log 主要实现数据库的一致性。
innodb 事务日志包括 redo log 和 undo log。
undo log 指事务开始之前,在操作任何数据之前,首先将需操作的数据备份到一个地方。redo log 指事务中操作的任何数据,将最新的数据备份到一个地方。
事务日志的目的:实例或者介质失败,事务日志文件就能派上用场。
redo log
redo log 不是随着事务的提交才写入的,而是在事务的执行过程中,便开始写入 redo 中。具体的落盘策略可以进行配置 。防止在发生故障的时间点,尚有脏页未写入磁盘,在重启 MySQL 服务的时候,根据 redo log 进行重做,从而达到事务的未入磁盘数据进行持久化这一特性。RedoLog 是为了实现事务的持久性而出现的产物。
undo log
undo log 用来回滚行记录到某个版本。事务未提交之前,Undo 保存了未提交之前的版本数据,Undo 中的数据可作为数据旧版本快照供其他并发事务进行快照读。是为了实现事务的原子性而出现的产物,在 MySQL innodb 存储引擎中用来实现多版本并发控制。
MySQL的 binlog 是记录所有数据库表结构变更(例如 CREATE、ALTER TABLE)以及表数据修改(INSERT、UPDATE、DELETE)的二进制日志。binlog 不会记录 SELECT 和 SHOW 这类操作,因为这类操作对数据本身并没有修改,但你可以通过查询通用日志来查看 MySQL 执行过的所有语句。
MySQL binlog 以事件形式记录,还包含语句所执行的消耗的时间,MySQL 的二进制日志是事务安全型的。binlog 的主要目的是复制和恢复。
binlog 有三种格式,各有优缺点:
statement: 基于 SQL 语句的模式,某些语句和函数如 UUID, LOAD DATA INFILE 等在复制过程可能导致数据不一致甚至出错。
row: 基于行的模式,记录的是行的变化,很安全。但是 binlog 会比其他两种模式大很多,在一些大表中清除大量数据时在 binlog 中会生成很多条语句,可能导致从库延迟变大。
mixed: 混合模式,根据语句来选用是 statement 还是 row 模式。
MVCC, 即多版本并发控制。MVCC 的实现,是通过保存数据在某个时间点的快照来实现的。根据事务开始的时间不同,每个事务对同一张表,同一时刻看到的数据可能是不一样的。
对于 InnoDB ,聚簇索引记录中包含 3 个隐藏的列:
我们拿上面的例子,对应解释下 MVCC 的实现原理,如下图:
如图,首先 insert 语句向表 t1 中插入了一条数据,a 字段为 1,b 字段为 1, ROW ID 也为 1 ,事务 ID 假设为 1,回滚指针假设为 null。当执行 update t1 set b=666 where a=1 时,大致步骤如下:
因此可以总结出 MVCC 实现的原理大致是:
InnoDB 每一行数据都有一个隐藏的回滚指针,用于指向该行修改前的最后一个历史版本,这个历史版本存放在 undo log 中。如果要执行更新操作,会将原记录放入 undo log 中,并通过隐藏的回滚指针指向 undo log 中的原记录。其它事务此时需要查询时,就是查询 undo log 中这行数据的最后一个历史版本。
MVCC 最大的好处是读不加锁,读写不冲突,极大地增加了 MySQL 的并发性。通过 MVCC,保证了事务 ACID 中的 I(隔离性)特性。
MySQL内容确实比较多,写出来的基本是常用的,另外大家还可以去看看MySQL锁相关知识以及分库分表等,关于MySQL基础大家可以看我以前写的一篇:MySQL基础