MySQL 索引
MySQL索引
索引
索引就相当于一本书的目录,有了目录,就会大大增加查找的效率
但是有得必有失
索引要付出的代价:
消耗了更多的空间
虽然提高了查找的效率,但是新增 修改 删除的效率降低了
尽管如此,添加索引大部分情况下还是有意义的,毕竟查找是高频的操作,还是值得的
索引的基本操作
查看索引
show index from 表名;
创建索引
create index 索引名 on 表名(列名) ;
创建索引还是一个比较低效的操作,而且十分的危险
删除索引
drop index 索引名 on 表名;
删除索引的操作也是十分危险的
索引背后的数据结构(重点)
索引为什么查找的效率比较高/索引背后是什么数据结构?
首先回忆一下之前学过哪些数据结构
顺序表
链表
栈
队列
优先级队列
二叉树 二叉搜索树
哈希表
ArrayList与LinkedList 有哪些区别?
首先,ArrayList的底层是顺序表,LinkedList的底层是链表
接下来就是一个==误区==:ArrayList查找比较快,LinkedList增加删除比较快,==这是错的==
首先ArrayList查找并不快,只是具备随机访问的能力
随机访问: 根据下标,获取元素
查找还是根据值来获取元素的位置,indexOf才是查找
ArrayList 查找的时候还是要根据下标进行遍历的,O(N) 并没有优势
LinkedList 增加和删除 也不快,在首尾进行增删还是可以的,O(1),在中间进行插入,还是要进行
遍历寻找节点,再进行插入
add(n,value); 还是通过下标进行描述的
所以从中间插入删除,之所以是O(N),并不是链表不行,而是linkedList方法的封装不太行
哈希表和二叉树 二叉搜索树 都不适合作数据库的索引
哈希表虽然增删查改的很快O(1) ,但是它只能查询 值相等 的情况,无法处理< > between and 之类的比较大小的 范围查询
二叉搜索树的查询速度是O(N)[最坏情况] , 即使是红黑树 AVL树 (比较平衡的二叉搜索树)的查询速度也就只有O(logN)
要是数据库的数据很多,树的高度就会很高,查询的时间就会更长
所以,数据库的索引就有了一个专门的数据结构-- B+树(大部分的数据库都是B+树)
首先要知道什么是B树(也叫做是B-树, 注:这不是减号,而是连字符)
B数是一个N叉搜索树,每个节点上最多包含N-1个值,B树的每个相邻的值是都是有范围的,这样子同样的元素的树的高度就会小很多,IO的次数就会减少很多,效率也会提高
但是索引的数据结构是B+树
B树的每个节点N个值,就会分出N+1个区间
B+树N个值,会分成N个区间
B树的值不会重复出现
B+树的值会重复出现(父元素的值会在子元素中以最大值或者最小值出现)
到了叶子结点,B+树会将所有的叶子结点以链表的形式首尾相连,这样子十分利于范围查找
由于叶子节点是全集数据,所以只要将每一行的每一条记录关联到叶子节点上,非叶子节点只要保存 索引列,此时非叶子节点占用的空间很小,就可以在内存中缓存,查询的时候进一步减少了硬盘的IO
通过以上的讲解,面试题:谈谈索引是干啥的?
- 索引是干啥的?
- 索引付出的代价
- 索引背后的数据结构
事务(transaction)
原子性:一个事务的所有操作要么不间断地全部被执行,要么一个也没有执行。
举一个简单的例子,使用移动支付转账的时候,总体上要进行两步,将自己的钱减掉x,将对方的钱加上x,一旦,在我的钱减去x之后,银行的服务器挂了,对方的钱还没有进行操作,此时,就会很麻烦.
为了防止出现上面的情况,就希望按照原子的方式完成
要么全部执行完
要么全都不执行(要是执行一半是出现问题,能够自动恢复如初)
在事务的执行过程中,当执行过程中出现问题的时候,自动将前面的SQL效果还原 这就是回滚(rollback)
使用
- 开启事务: start transaction
- 执行多条SQL语句
- 回滚或者提交:rollback/commit
事务的开启,提交 回滚一般都是通过代码来实现的
事务的几大特性
原子性 : 事务的核心,能够将多条SQL打包成一个整体,要么执行完,要么就不执行,如果执行过程中出错,就进行回滚
一致性; 事务执行前后,数据处在"一致"的状态(数据能够对得上)
持久性:事务进行的改动,都是写到硬盘上的, 不会随着程序重启/主机重启而丢失
隔离性: (最复杂) 多个事务,并发执行的时候,事物之间能够保持"隔离",互不干扰
MySQL本质上就是一个服务器,执行SQL语句其实就是客户端将SQL发给服务器,让服务器去执行,事务也是发给服务器去执行
并发执行:同一时刻,多个客户端都想服务器发送了事务,让服务器去执行
如果这些并发执行的事务,操作的是不同的数据库/不同的表,就没事
要是这些操作的是相同的数据库,相同的表,就可能会出现冲突
隔离性存在的意义就是让并发执行事务的时候,尽量不出问题(问题控制在可控的范围内)
脏读: 一个事务A在修改数据,提交之前,正好被另一个事务B读取了数据,此时A就极有可能修改数据再提交 ,此时B事务独到的就是"无效的数据"也就是脏数据
如何解决脏读问题?
在提交之前,不能读,提交之后才能读(写完了才能读)
这就相当于是进行写加锁
没有对写操作加锁,写 和 读 是完全并发的 并发性最高,但是隔离性最低
对写操作加锁,并发性降低(效率降低),但是隔离性提高了(准确性提高了)
不可重复读:在一个事务A中,多次读取同一个数据,结果发现每次读到的数据不一样(也就是说读的时候被人改了)
不可重复读要通过读加锁 来 解决 (读的时候不能进行修改)
引入读加锁 ,进一步降低了并发性(效率降低) 但是 隔离性提高了(数据的准确性提高了)
幻读: 一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了"幻影"
要想解决幻读 问题 ,方法就是串行化
在进行了写加锁 读加锁 串行化 之后,并发程度已经降到了最低(效率最低),但是 隔离性最高(数据最精确)
上面说的脏读 不可重复读 幻读 都是在并发执行事务中 可能会带来的影响,这些影响不一定是bug,因为要看实际需求中要求数据的精确程度
衡量是不是bug的唯一标准就是符不符合需求
MySQL给我们提供了"隔离级别"选项 ,给了四个档位,根据实际需求,选择不同的档位
1.read uncommitted 允许读未提交的数据, 并发程度最高,隔离性最低,可能存在脏读/不可重复读/幻读 问题
2.read committed 只能读提交后的数据,相当于写加锁,并发程度降低,解决了脏读,可能存在不可重复读 幻读 问题
3.repeatable read 相当于读和写都加锁,并发程度再降低,隔离性在提高,解决了脏读 不可重复读 ,可能存在幻读问题
4,serializable 严格执行串行化,并发程度最低,隔离性最高,解决了脏读 不可重复读 幻读,数据最精确 ,但是效率较低
以上的设置都要在MySQL的配置文件 my.ini中设置 ,根据不同的寻求场景,就可以设置不同的档位
通过以上的讲解 , 面试题:
- 事务是干啥的?(从原子性切入)
- 事务有哪些特性
- 隔离性在并发事务中有哪些问题,以及如何解决(脏读 不可重复性 幻读)
- MySQL的隔离级别有哪些,和上面的问题有哪些对应