文章参考的是javaGuide, https://github.com/Snailclimb/JavaGuide/blob/master/docs/java/multi-thread/2020%E6%9C%80%E6%96%B0Java%E5%B9%B6%E5%8F%91%E8%BF%9B%E9%98%B6%E5%B8%B8%E8%A7%81%E9%9D%A2%E8%AF%95%E9%A2%98%E6%80%BB%E7%BB%93.md 这里记录属于个人的查漏补缺,如果小伙伴需要更加全面和详细的资料,请看上面的链接呦!

1、查询缓存的作用?

执行查询语句的时候,会先查询缓存。需要开启查询缓存。使用缓存虽然能够提升查询性能,但也带来了额外的开销,每次查询后都做一次缓存操作,失效后销毁

2、并发事务会带来那些问题?

脏读、不可重复读、幻读、丢失修改

3、大表优化的策略

1、限定数据的范围
2、读写分离
3、垂直分区
4、水平分区

4、分库分表之后,id主键怎么处理?

要是分成了多个表,每个表的id肯定不能从1开始累加,需要一个全局id来支持。
生成全局id的几种方式:

  • uuid:不适合做主键,因为太长了,并且无序。
  • 自增id:两台数据库设置不同的步长,生成不重复id的策略实现高可用。但是成本高。
  • 利用redis生成id。性能好又方便,但是引入了新组件,编码更复杂

5、一条sql语句在mysql中怎么执行?


yml redis数据库索引可以改吗 redis有索引吗_redis


组件:

  • 连接器:身份认证、权限认证
  • 查询缓存:执行查询语句的时候先查询缓存。(8.0之后移除了)
  • 分析器:没有命中缓存,就进行分析这条sql语句要做什么事情
  • 优化器:按照mysql认为的最优的方法去执行
  • 执行器:执行语句,从存储引擎返回数据

对于查询的sql语句执行:

权限校验——查询缓存——分析器——优化器——权限校验——执行器——引擎

例如:select * from tb_student A where A.age='18' and A.name=' 张三 '; 先检查该语句是否有权限,没有直接返回错误信息。有的话就查询缓存,缓存有结果就直接返回没有就进入分析器进行词法分析。比如提取select,表名tb_student,id=1等信息。没有错误就进入优化器确定执行方案。然后进行权限校验,有权限就会调用执行引擎进行执行,然后返回结果。

对于更新的sql语句执行:

分析器——权限校验——执行器——引擎——redo log prepare——binlog——redo log commit

例如:update tb_student A set A.age='19' where A.name=' 张三 ';

和上条查询过程差不多,只不过要记录日志。
查询缓存,有的话就调用引擎,写入这行数据,innodb引擎把数据保存在内存中,同时记录redo log,此时redo log进入prepare状态,告诉执行器,执行完成了可以随时提交。执行器收到通知后记录binlog,然后调用引擎提交redo log为提交状态,更新完成。
这里利用两个日志模块,保证了数据的一致性。

6、一条sql语句执行很慢的原因有哪些?


分两种情况:
1、偶尔很慢的情况
那说明sql语句本身应该是没什么问题的,所以可能的情况是一下几点:

  • 数据库在刷新脏页。我们在更新数据时,会立马把内存中对应的数据更新了,但是更新的字段不会马上同步持久化到磁盘,而是先记录到redo log中,空闲的时候在同步到磁盘。脏页指的是内存和磁盘中数据不一致。那么什么情况下会刷新脏页呢?
    (1)redo log被写满。没办法等到空闲时候在同步到磁盘了,只能暂停其他操作,全心全意的同步数据。
    (2)内存不够用。查询数据过多,内存需要淘汰一部分页,如果是干净页直接淘汰,脏页需要刷。
  • 拿不到锁。可以用show processlist查看当前的状态,看是不是拿不到锁。
    2、一直都很慢
  • 没有走索引。
  • 走错索引了。由于统计的失误,导致系统没有走索引,而是走了全表扫描。

7、索引那么多优点,为什么不每一张表都建立索引呢?

  • 索引的维护。当对表中的数据进行增删改查时,索引也要动态维护。
  • 占用空间。处理数据占据空间之外,索引也需要占用空间,聚簇索引占用空间更大。
  • 时间消耗。创建和维护索引需要耗费时间。

8、什么时候使用索引比较好?

1、经常用于搜索的列,可以加快搜索速度。
2、经常使用where子句的列,加快条件判断速度
3、需要排序的列,因为索引已经排序
4、中大型表适合索引,特大型表维护开销太大,不适合。
5、用于连接的外键,可以加快连接速度。

9、什么是覆盖索引?

如果一个索引包含(覆盖)了所有需要查询的字段,就称为“覆盖索引”。可以避免“回表”.意思就是查询的数据在叶子节点都存在,不需要返回非叶子节点在走一遍。

10、选择索引和编写利用索引的三个原则?

  • 单行访问很慢。如果服务器从存储中读取一个数据块只是为了获取其中一行,就浪费了很多工作,所以最好读取的块中包含尽可能多的需要的行,使用索引可以创建位置引,提升效率。
  • 顺序访问效率高。首先,顺序io不需要多次磁盘寻道。其次,不需要额外的排序操作。
  • 索引覆盖。尽可能的索引覆盖,不进行回表查询。

11、为什么索引能够提高查询速度呢?

mysql的存储结构是记录都存储在页里面。

  • 每个数据页可以组成一个双向链表
  • 每个数据页中的记录可以组成一个单向链表。每个数据页会为里面的记录生成一个页目录,如果通过主键查找某条记录的时候,可以在页目录中通过二分法快速定位到对应的,然后遍历该槽对应分组中的记录找到指定的记录。如果通过非主键遍历,从最小记录开始依次遍历单链表中的每条记录。
    补充理解:
    参考链接:添加链接描述

简单来说,数据页包括两部分:一部分存储数据记录,按照记录的大小用指针连接起来。(单向链表);里那个一部分存储数据页的页目录,用于加速查找。
例如:select * from user where indexname = ‘xxx’
1、定位到记录所在页:遍历双向链表,找到页
2、定位页内的记录:由于不是主键查询,遍历单向链表
显然,这样的查询速率是很慢的。

所以要使用索引:将无序数据变为有序,提高查询速度。

yml redis数据库索引可以改吗 redis有索引吗_java_02


没有索引的话我们就需要遍历双向链表来定位对应的页,现在通过页目录就可以使用二分法进行定位了。其实底层结构就是B+树。索引的作用就是书本的目录作用,如果没有索引就要一页一页翻书本去找,有了目录直接查询目录找到对应位置就行了。

redis

参考:

1、缓存的作用?

缓存就是用空间换时间,对于cpu cache来说是为了解决内存和cpu速度不匹配的问题;对于数据库来说,是为了避免用户在请求数据的时候获取速度过慢。

2、为什么用分布式缓存?不用本地缓存?

本地缓存:
1、JDK自带的hashmap和concurrentHashMap。大部分场景不会用。
2、ehcache、guava cache,spring cache。这三种使用较多。

好处:低依赖、轻量、简单、成本低
坏处:对分布式架构不友好:本地缓存无法共享;受当前系统内存影响,内存占用多,缓存容量就少。

分布式缓存:
好处:即使同一个服务部署在不同的机器上,使用的也是同一份缓存。
坏处:需要引入额外的服务。比如:redis,memcached等

3、缓存读写模式/更新策略

  • cache aside patten
    1、写:更新db,删除缓存
    2、读:cache读,读到返回;读不到从db返回,然后将数据放入cache
  • read/write through patten
    服务端将cache作为主要操作对象
    1、写:查cache,不存在直接更新db;存在,先更新cache,然后cache服务自己更新db
    2、读:读cache,读到返回;读不到,从db读,然后写入cache后返回响应
  • write behind patten
    与第二个区别:
    read/write through patten同步更新cache和db, write behind patten只更新cache,异步批量的更新db。所以对于经常变化的数据来说,这种方式很适合。
    例如一篇文章的访问量,这是针对一项数据一直变化,可以采用 write behind patten方式,点赞500次不用修改500次,只需要批量修改一次即可。

4、为什么用redis作为缓存?

主要是为了提高用户体验。

  • 高性能
    redis是基于内存的数据库,所以访问速度是很快的。
  • 高并发
    直接操作缓存 可以承受的请求量 远远大于直接访问数据库。

5、redis为什么不用多线程呢?

redis是单线程的。redis 4.0之后加入了对多线程的支持。
不使用多线程的3个原因:

  • 单线程更容易维护
  • redis的瓶颈不是cpu,而是内存和网络
  • 多线程可能会出现死锁、上下文切换问题,影响性能。
    虽然说redis是单线程,但是通过io多路复用技术可以监听大量的客户端连接。

6、缓存中为什么要给数据设置过期时间呢?

1、如果所有数据一直保存的话,占用内存就会出现oom异常。
2、还有的业务场景要求数据只保持一断时间就行。比如验证码60s失效等。

7、redis是怎么判断数据是否过期的,删除策略是啥?

通过过期字典来保存过期时间。

删除策略:

  • 惰性删除:用到的时候才判断key是否过期
  • 定期删除:每隔一段时间就删除过期key
    但是仅仅依靠过期时间也可能造成oom,怎么办呢?内存淘汰机制。
    内存淘汰机制有六种:
  • volatile-lru:从设置过期时间的key中选择最近最少使用的数据淘汰
  • volatile-ttl:从设置过期时间内的key中选择即将过期的数据淘汰
  • volatile-random:从设置过期时间的key中随机选择数据淘汰
  • allkeys-lru:从所有数据中选择最近最少使用的数据淘汰
  • allekys-ttl:从所有数据中选择即将过期的数据淘汰
  • allkeys-random:从所有数据中随机选择数据淘汰