20231111
回顾
1.聚合查询
2.联合查询(内连接,外连接,自连接)重点
3.子查询
4.合并查询(union):需要保证列数和类型得匹配
可以合并多个表,or只能连接表内
MySQL 索引事务
索引(index)更多翻译成下标
目录
在数据库中进行条件查询也是要遍历表的
数据库是把数据存储在硬盘上的,此处的O(N),比平时的慢很多,因为平时是指内存
因此给数据库也引入索引来 提高查询的速度
索引的特点
1.加快查询的速度
2.索引自身也是一定的数据结构,也要占据存储空间
3.当我们进行新增删除修改的时候,也需要针对索引进行更新,有额外的开销
删除修改搭配条件语句
先条件查找[变快]
再修改[变慢]
在没有条件的时候或者不能使用索引的时候,速度肯定会变慢
索引适用的场景
1.存储空间比较充裕(索引对于空间要求不高)
2.查询较多,增加删除修改不多
读多写少的场景是很常见的
通过sql如何操作索引?
1.查看索引
show index from 表名
查看是否有索引,有几个索引
primary key和unique这两个约束都会自动生成索引
mysql中的primary key 和 unique 和 foreign key 都会默认生成索引
一个表的索引可以有多个,每个索引,都根据具体的列来展开的
2.创建索引
create index 索引名 on 表名(列名);
这个创建操作也是比较危险的操作
假设这个表是空着的或者数据比较少,无所谓
但是如果本身有很多数据,此时创建索引操作,就会触发大量硬盘IO
3.删除索引
drop index 索引名 on 表名;
删除索引也是一个危险操作
在创建索引的时候,一定要在建表之初就规划好.
实际开发中已经用了很久的表相加索引,只能曲线救国
可以另外搞一个机器搭建数据库,把生产环境的数据表创建好加上索引,再导入数据,最后用新的机器代替旧的机器
这里导入数据是不影响生产环境正常的工作的(慢慢导)
索引底层的数据结构的实现
索引其实是通过额外的数据结构,对表里的数据进行组织
使用什么样的数据结构,和表占用的空间,都是有很大的影响的
ArrayList底层是数组可以进行随机访问,当使用随机访问进行读写时,速度比较快
查找使用时indexOf的方法,要遍历ArrayList
尾插,尾删比较快,头插/中间插入/删除 比较慢
随机访问!=查找
LinkedList
进行头插头删尾插尾删都是O(1)的复杂度
进行查找/中间位置的删除都是O(n)的操作
LinkedList 是否遍历过程更快?
错误的,因为链表访问下一个元素通过next引用,相比顺序表的++操作,多了一次访问内存的操作,++用寄存器会更快
是否更加节省内存呢?
不是,每个节点都要额外的内存存储指针域
使用LinkedList在中间位置插入,为啥是O(N)??
因为Java接口设计不好
LinkedList通过add进行插入
这里std::list就更合理一点
insert(值,迭代器)
迭代器
O(1)确定迭代器的位置算在其他代码上的,就是O(1)的复杂度
二叉搜索树,如果元素比较多,树的高度就很高,就会增加查询过程中的比较次数
数据库查询的时候,经常指定的条件不是按照相等来比较的
但是数据库经常有< > between and这样的范围查找,哈希表就无能为力了
这里只能比较相等
因此数据库的索引使用了B+树作为数据结构~~
要想理解B+树,先得了解B树
B树也叫B-树 是连字符,不是减号
B树是一个N叉搜索树
N叉搜索树就是在二叉搜索树进行了扩展~~
一个节点可能包含n个值,n个值就划分出了n+1个区间
同样高度的树,能表示的元素相比于二叉搜索树上就多了不少
通过b树来查询的时候,论比较次数,比二叉搜索树还要多
但是,这里的关键就在于同一个节点的这些key是一次硬盘io就读出来的
(总的比较次数增加了,硬盘io的次数就少了)
B+树
n个key不是划分成N+1个区间,而是N个区间
比如 8 15
只有小于8和8到15之间了,没有大于8的了
在叶子节点会用链表串起来
B+树的特点:
1.也是N叉搜索树,每个节点包含N个key,划分出N个区间
2.每个节点中,会存在一个'最大值',换成最小值也是一样
3.每个节点中的key都会在子树中重复出现
重复出现带来的好处就是所有的数据都包含在叶子结点这一层(数据全集)
4.把叶子结点使用链式结构相连
如果没有这个链式结构,就需要反复回溯,就很麻烦了
查询稳定
查询任何一个节点都是需要通过根节点查询到叶子结点
(B树有时候硬盘io多,有的时候少)
按照上述结构来存储的话,就只需要在叶子结点来存储数据行
其他的非叶子节点只存储key即可
而这个key占用空间是比较小的
100w个key才4MB
这个时候就可以在查询的时候只进行内存的比较,减少了硬盘IO的次数
数据库的事务
很多时候进行的多个操作,期望能够打包到一起,共同执行
原子性,
一致性,
隔离性,
持久性
rollback 回滚 来保证这种原子性的
怎么恢复回去的???
数据库对于事务这里有特殊的机制(undo log + redo log)
记录之前的数据,进行的操作,
数据库中间挂了,重启之后就会查看日志,看看是否有进行了一半的事务,如果有就进行回滚
事务这个东西,虽然是让数据更靠谱了,但是也付出了效率的代价
原子性,一致性,隔离性,持久性
持久性:事务的任何修改,都是写入硬盘的
隔离性:多个事务并发执行的时候,可能带来一些问题,通过隔离性来对这问题进行权衡,看你是希望数据尽量准确还是速度快
并发是指一个服务器涉及多个客户端,多个客户端同时修改一个表,就会产生一个bug
1.脏读问题:
两个事务修改一个数据,避免读到错误的数据
加锁,写的时候不能读,写完并且提交事务之后才可以让别人读了
2.不可重复读
又修改了一下,重新提交 代码又变了
是写加锁前提下导致的问题
刚刚约定的是写的时候不能读,没说读的时候不能写
给读操作也加锁,读的时候也不能写
通过锁让并行程度又降低了
3.幻读问题
事务1,2
事务1:修改数据,提交
事务2:开始读数据
事务3:新增了一个其他的数据,此时事务2就可能出现,两次读取的结果集不一样
解决幻读问题:严格执行串行化,不再执行任何并发了
上述几个情况,是否真的算bug??
看情况,看要效率还是要数据的准确性
mysql在配置中,提供了隔离级别这样的选项,可以根据需求调整隔离级别
1.read uncommitted 读未提交,并行程度是最高的,也是最不靠谱的
2.read committed 读已提交,相当于给写操作加锁,隔离程度提高了,效率低了一点,但是更靠谱
可能出现不可重复读和幻读问题
3.repeatable read 给读写操作加锁了
4.serializable 串行化,让所有事务都是串行执行........效率最低,数据更靠谱
什么时候,效率大于准确性??
点赞数.....当点击量达到10w+
关注的就是点击之后,快速响应就行,没必要那么精确
start transaction;
开启事务
sq1;
sq2;
sq3;
commit;事务完毕
rollback 告诉服务器要进行回滚,恢复回去 (一般不在控制台敲)
一般在java代码里,代码中控制开启事务,控制执行sql
结果某个sql抛出异常,在catch语句中,捕获到异常,并且使用rollback
上述内容,为了应对一般的面试题
JDBC编程
通过java代码来操作数据库
实际开发中,绝大多数情况,都是通过代码操作数据库的,调试,测试验证环境才会涉及到控制台
本质上还是操作sql
数据库是一个类别
1.mysql
2.oracle
3.sql server
4.sqlite
操作数数据库前提是数据库提供api
如果api特别多,也可以成为SDK(软件开发工具包)
原有的api不变,在这个基础上,加个封装层,适配到JDBC这一套接口上
后续学到操作数据库的框架本质上也是jdbc的封装
1.引入jdbc的驱动包
.class文件打包成.jar这样的压缩包
实际使用不用对jar进行解压缩,只要吧jar包导入即可
2随便创建一个目录,拷贝进去
JDBC方法有点多,注意步骤多练习
ip地址,用来描述一个主机在网络上的位置的机制每个同学电脑ip可能都是不同的此处统一写成127.0.0.1
loopback - 环回ip 表示本机
端口号:一个主机上,有很多服务器程序,使用端口号来区分不同的服务程序
高内聚,低耦合
耦合,两个东西之间的关联程度,关联程度越密,耦合越高
内聚:把有关系的代码放到一起,不要放到东一处西一处的
1.数据源 DataSourse
2.connection 先建立连接,才能进行通信 基于dataSourse才能建立连接
3.PreparedStatement 语句 基于连接来生成的,语句对象也是要发给服务器的
update只需要返回一个整数
Query返回的是一个ResultSet (结果集)
结果集指的就是select语句得到的临时表