java面试题/笔试题 汇总

高频面试问题分享

一、JVM相关

1.jvm的内存结构

2.jvm哪些部分会出现堆内存溢出

3.

一、Mysql相关

1、mysql数据结构(B+Tree)(理解透彻)

1)、什么是索引(Index)?

本质是帮助MySQL高效获取数据数据结构MySql中主要应用的索引数据结构为B+Tree

2)、索引结构类型有哪些?

Mysql存储引擎主要有MySIAMInnoDB。而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BTree索引哈希索引全文索引等等

★3)、mysql数据和索引存储位置?

MySIAM的索引和数据分两个文件进行存储:MYI文件存储索引(B+树)、MYD文件存储数据

InnoDB的索引和数据存储在一个文件中:ibd文件(B+树)

4)、存储数据结构?

MySIAM、InnoDB两种存储引擎都是基于B+树数据结构存储表数据的。不同之处是:MySIAM的B+树只存储了索引key值地址,真正的数据存储在别的地方

InnoDB 存储引擎中的B+树既存储了索引也存储了数据

B+Tree结构示例图

5)、节点数据项存储的是什么?

MySIAM非叶子节点存储的是索引列的值叶子结点存储的为真实数据所在的地址

InnoDB

对于非主键索引(非聚集索引):非叶子结点存储的是索引列的值叶子结点存储的为主键ID值

对于主键索引(聚集索引):非叶子结点存储的是ID值叶子结点存储的为完整的数据

★6)、为什么使用B+tree

由于数据存储于物理磁盘,所以要尽量减少从磁盘IO数据的次数,有效手段有:

1、磁盘局部预读原理,预读的大小通常为Page的倍数;

2、选取合适的数据结构存储数据,从磁盘IO次数越小越好,如BTree,渐进复杂度为O(h)=O(logdN)O(h)=O(logdN),一般实际应用中,出度d 是非常大的数字,通常超过100,因此树的高度h非常小(通常不超过3层可容纳百万级数据)。所以,B+tree作为mysq数据库的数据结构搜索效率是很高的

7)、B+tree与B-tree联系和区别

(1)、B+tree是B-tree的变体;

(2)、在B-tree的基础上增加了叶子结点间的顺序访问指针,B+Tree提高了顺序访问的性能;

(3)、B-tree每个结点的指针上限为2d+1,B+tree每个结点的指针上限为2d;

(4)、B+tree非叶子结点只存储索引值,叶子结点存储真实数据,B-tree所有结点上都存储数据;

8)、聚集索引、非聚集索引

聚集索引:又叫主键索引,是指数据库表行中数据的物理存储顺序与数据的逻辑顺序相同,一张表中只允许存在一个聚集索引,对于mysql来说一般就是主键

若无主键则为表中第一个非空的唯一索引,还是没有,就采用InnoDB存储引擎为每行数据内置的ROWID 作为聚集索引 ;

聚集索引就是按照每张表的主键构造一颗B+树,同时叶子节点中存放的即为整张表的记录数据

聚集索引的叶子节点称为数据页,聚集索引的这个特性决定了索引组织表中的数据也是索引的一部分。

非聚集索引:又叫辅助索引、二级索引。是指除了聚集索引外的其他索引,该索引中索引的逻辑顺序与磁盘上行的物理存储顺序不同,一个表中可以拥有

多个非聚集索引。数据的逻辑顺序可能相邻,但是数据的实际存储物理地址可能相差十万八千里 ;

非聚集索引的叶子节点存储主键

9)、覆盖索引

这个概念就是指select的数据列只用从索引中就能够取得,不必从聚集索引中的叶子结点数据项中读取,换句话说查询列要被所使用的索引覆盖。 索引是高效

找到行的一 个方法,当能通过检索 索引就可以读取想要的数据,那就不需要再到数据表中读取行了。如果一个索引包含了(或覆盖了)满足查询语句中字段与条件的数据

就叫做覆盖索引。在mysql中只能使用BTree索引做覆盖索引、Hash索引不行 如果实现了覆盖索引,在explainExtra列可以看到“Using index”的信息

10)、查询过程

(1)、对于聚集索引(主键索引)来说,也就是通过主键查询,一次查询就能查询到具体的行数据信息

(2)、对于非聚集索引来说(唯一索引、普通索引、全文索引)

如果需要查询的数据列在索引中,如A+B联合索引,根据A去查询B,则通过一次查询就能直接拿到索引上的数据,也就是覆盖索引现象;

如果需要查询的数据不在索引中,则需要先去普通索引树中进行第一次查找得到行数据的主键值,然后通过主键值去主 键索引树中第二次搜索得到真实

数据,这种需要二次查询的现象叫做回表查询

详细解释:

从普通索引无法直接定位行记录,那普通索引的查询过程是怎么样的呢?通常情况下,需要扫码两遍索引树。

例如:select * from t where name='lisi';*是如何执行的呢?

11)、B+Tree性质

(1).我们知道IO次数取决于B+树高度h,假设当前数据表的数据为N每个磁盘块的数据项的数量是m,则有h=㏒(m+1)N,当数据量N一定的情况下,m越大h越小;而m = 磁盘块的大小 / 数据项的大小,磁盘块的大小也就是一个数据页的大小,是固定的,如果数据项占的空间越小数据项的数量越多树的高度越低。这就是为什么每个数据项,即索引字段要尽量的小,比如int占4字节,要比bigint8字节少一半。这也是为什么b+树要求把真实的数据放到叶子节点而不是内层节点,一旦放到内层节点,磁盘块的数据项会大幅度下降,导致树增高。当数据项等于1时将会退化成线性表。

(2).当B+树的数据项是复合的数据结构,也就是联合索引比如(name,age,sex)的时候,b+树是按照从左到右的顺序来建立搜索树的,比如当(张三,20,F)这样的数据来检索的时候,b+树会优先比较name来确定下一步的所搜方向,如果name相同再依次比较age和sex,最后得到检索的数据;但当(20,F)这样的没有name的数据来的时候,b+树就不知道下一步该查哪个节点,因为建立搜索树的时候name就是第一个比较因子,必须要先根据name来搜索才能知道下一步去哪里查询。比如当(张三,F)这样的数据来检索时,b+树可以用name来指定搜索方向,但下一个字段age的缺失,所以只能把名字等于张三的数据都找到,然后再匹配性别是F的数据了, 这个是非常重要的性质,即索引的最左匹配特性原则

12)、B+Tree IO数据查找示意图

2、mysql优化

1)、优化SQL语句层面(理解透彻)

1)、尽量避免使用select *;

2)、规范sql语句大小写,sql是有缓存的,避免每次都需要解析;

3)、使用exsits代替in,要更高效;

4)、mysql sql解析执行过程从右至左,基于这个规则,from后面能过滤掉更多数据的基础表放后面,where后面能过滤掉更多数据的查询条件放后面;

5)、查询条件中用相同类型去查询,比如避免数值列用字符串查询条件;

6)、合理使用索引

​
                1、为合适的列添加索引(主键、唯一索引、组合索引);
                2、尽量建立联合索引,也省空间成本;
                3、尽量使用覆盖索引;
                3、避免以下会使索引失效的操作
                    1)、索引列有null值不走索引
                    2)、使用is null或is not null不走索引
                    3)、各种负向查询not ,not in, not like ,<> ,!= ,!> ,!<  不会使用索引
                    4)、like将%放左边不走索引
                    5)、查询条件的数据类型做了隐式转换
                    6)、使用in或union代替or,or两侧有非索引列就不会走索引
                    7)、尽量保持索引列干净,不在索引列上使用函数转换、运算
                    8)、联合索引要遵循最左匹配原则.
                            如建立联合索引(A,B,C),查询顺序如下:
                            ABC会走索引,AB会走索引,A也会走索引,但是不能断开,如AC|CA|BC|CB|B|C都不会走索引
                    9)、使用比较运算或between会使联合索引从使用比较运算的下一个索引处断开

7)、explain命令进行sql慢查询排查

对于执行查询很慢的sql,通常对sql语句执行explain命令进行分析,具体信息如下:

1. id //select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序,id相同,执行顺序从上至下 //id值越大,优先级越高,越先执行

2. select_type //查询类型 SIMPLE、PRIMARY、SUBQUERY、DERIVED、UNION、UNION RESULT

3. table //正在访问哪个表

4. partitions //匹配的分区

5. type //访问的类型 效率从快到慢:NULL>system>const>eq_ref>ref>ref_or_null>index_merge>range>index>ALL

6. possible_keys //显示可能应用在这张表中的索引,一个或多个,但不一定实际使用到

7. key //实际使用到的索引,如果为NULL,则没有使用索引

8. key_len //表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度

9. ref //显示索引的哪一列被使用了,如果可能的话,是一个常数,哪些列或常量被用于查找索引列上的值

10. rows //根据表统计信息及索引选用情况,大致估算出找到所需的记录所需读取的行数,这个数量越小越好

11. filtered //查询的表行占表的百分比

12. Extra //包含不适合在其它列中显示但十分重要的额外信息

2)、优化架构方面(了解)

在数据达到一定量级以后,需要对数据库从主从、分库分表数据分片方面进行优化:

读写分离:主节点写,从节点读

分库:根据业务或者其他维度把数据存放到不同数据库

分表

1、水平分表:字段都一样,分多张表存放不同时间范围或不同维度的数据,如实时数据表、历史数据表。

2、垂直分表:将不同字段放在多张表,使用外键关联。

常用分库分表中间件:阿里的Cobar及开源社区基于Cobar维护的Mycat等。

3、mysql事务(理解透彻)

1)、事务有哪些特性?

  • 原子性:事务中所有操作要么全部提交成功,要么全部失败回滚,不能出现一部分失败,一部分成功的现象;

    • 一致性:指在事务的执行前后保持数据库的一致性;

      • 隔离性:一个事务所做的修改在最终提交之前,对其他事务是不可见的;

        • 永久性:一旦事务提交,它所做的修改将会永久保存到数据库中,及时系统发生崩溃,事务执行结果也不会丢失;

2)、哪几种事务隔离级别,会出现的问题?

事务隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted)
不可重复读(read-committed)
可重复读(repeatable-read)
串行化(serializable)

3)、脏读、不可重复读、幻读

  • 脏读一个事物读到了另一个事务尚未提交的数据,不符合事务的隔离性。

    • 不可重复读同一个事务中对同一行记录两次读出来的结果不一样,原因就是第二次读到了其他事务修改提交的数据。

      • 幻读同一个事务中针对同一范围内的数据两次读出来的结果不一样,原因就是第二次读到了其他事务新增提交的数据。

4)、mysql和oracle默认事务隔离级别

  • mysql默认隔离级别:repeatable-read,但是一般会设置为read-committed,因为在实际业务中常常是:一个事务中需要读到别的事务提交修改的数据。

    • oraclel默认隔离级别:read-committed

4、mysql其它问题

1)、myISAM与 innodb 两种存储引擎的区别?

  • InnoDB 支持事务和外键,myISAM不支持

    • InnoDB 支持行锁,myISAM只支持表锁

      • InnoDB 的真实数据和索引存储在同一个文件中,而myISAM存储在两个文件中

      • InnoDB 不支持全文索引,而 MyISAM 支持。

2)、乐观锁与悲观锁

乐观锁:

思想为:乐观的认为本次事务操作数据不会有别的事务干扰,操作数据前不进行加锁,只是预先记录版本号,真正修改数据时再进行比对

如果版本号没变则修改数据,版本号变了则表面别的事务在本次事务过程中修改了数据,本次事务不修改数据。

具体步骤:

1、先查出版本号:select status,version from t_goods where id=#{id}

2、真正修改数据时进行版本号比对修改:update t_goods set status=2,version=version+1 where id=#{id} and version=#{version};

悲观锁:

思想为:悲观的认为本次事务一定会有别的事务干扰,操作数据前必须先加锁

常见实现方式为 for update加行锁: select ... from table where id = #{id} for update,这里注意,由于mysql锁是建立在索引上面的,所以查询条件必须用主键索引

否则会造成数据全表扫描

3)、char和vachar区别

char列长度固定,为创建表时声明的长度,长度值范围是1到255,当char值未填满指定长度时,其他空间会用空格进行填充,检索CHAR值时需删除尾随空格。

vachar长度为可变的,实际使用多少空间就占多少空间。

4)、使用varchar(255)的字段建索引可以吗?

理论上是可以的,拿Innodb和utf编码场景来说,索引长度极限为 767字节,utf8 编码时1个字符占3个字节,varchar 类型能建立索引的最大长度为

767/3 = 255,这也是为什么varchar最大长度为255的原因之一,但是实际业务场景中一般不会建如此大的索引,影响检索效率。

二、Redis相关

1、支持哪几种数据类型

支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

2、为什么读写速度很快

  • redis完全基于内存

    • 数据结构简单

      • 采用单线程,避免了加锁、释放锁、死锁、线程间切换等消耗

        • 使用多路I/O复用模型,非阻塞IO

      3、在你们项目有哪些应用场景

计数器:对 string 进行自增自减运算,从而实现计数器功能。redis 内存型数据库的读写性能非常高,很适合存储频繁读写的计数量。如每日登录次数计数。

热点数据缓存:将热点数据放到内存中。如首页排行榜数据,具有很大访问频次,使用zset可以实现基于score分数排序;。

会话缓存:用redis统一存储多台应用服务器的会话信息。当应用服务器不再存储用户的会话信息,也就不再具有状态,一个用户可以请求任意一个应用服务器,

从而更容易实现高可用性以及可伸缩性。

取数据交集、并集:基于redis set 的特性可以对共同好友进行很方便的查询。

分布式事务锁的使用:基于set lock requestId nx ex time 模式可以很方便编写分布式事务锁

4、基于什么协议

Redis 的通信协议是 Redis Serialization ,翻译为 Redis 序列化协议,简称 RESP

  • 在 TCP 层

    • 是二进制安全的

      • 基于请求 - 响应模式

      • 简单、易懂(人都可以看懂)

5、线程模型是怎样的?

20_来聊聊redis的线程模型吧?为啥单线程还能有很高的效率?_哔哩哔哩_bilibili

Redis 的线程模型:基于非阻塞的IO多路复用机制的线程模型,单线程

Redis 是基于 reactor 模式开发了网络事件处理器,这个处理器叫做文件事件处理器(file event handler)。由于这个文件事件处理器是单线程的,所以 Redis 才叫做

单线程的模型。采用 IO 多路复用机制同时监听多个 Socket,根据 socket 上的事件来选择对应的事件处理器处理这个事件。模型如下图:

上图得知,文件事件处理器的结构包含了四个部分:

  • 多个 Socket:客户单发起多个 socket,每个socket 会产生不同的事件,不同的事件对应着不同的操作

  • IO 多路复用程序:IO 多路复用程序监听着这些 Socket,当这些 Socket 产生了事件,IO 多路复用程序会将这些事件放到一个队列中。

  • 文件事件分派器:通过队列,将事件以有序、同步、每次一个事件的方式向文件时间分派器中传送,文件事件分派器将事件按类型分派给不同的事件处理器进行处理。

  • 事件处理器:分为连接应答处理器、命令请求处理器、命令回复处理器,每个处理器对应不同的 socket 事件。

    客户端向socket发一个请求 socket产生一个事件 事件叫AE READABLE IO多路复用监听到Scoket产生的事件 并将它添加到事件队列当中,分派器会从队列当中取出这个AE事件,让连接应答器来处理这个请求,连接应答器创建与客户端通信的sokect01 并将sokect01和AE事件绑定起来向命令请求关联(前端和后端连接),命令请求读取sokect01这段命令 写入内存当中 操作完成后会将AE Writable和命令回复绑定一起 向soket01输入本次结果,解除绑定

6、持久化机制是怎样的?

第一种:RDB,即 Redis 的内存快照,默认持久化机制,它是在某一个时间点将 Redis 的内存数据全量写入一个临时文件,当写入完成后,用该临时文件替换上一次持久化生成的文件,这样就完成了一次持久化过程,默认的文件名为dump.rdb

1)、触发RDB机制:

(1)、save触发方式:该命令会阻塞当前Redis服务器,执行save命令期间,Redis不能处理其他命令,直到RDB过程完成为止。具体流程如下:

(2)bgsave触发方式:执行该命令时,Redis会在后台异步fork出一个子线程进行快照操作,快照同时还可以响应客户端请求。具体流程如下:

(3)、自动触发自动触发是由我们的配置文件来完成的。在redis.conf配置文件中,里面有如下配置,我们可以去设置:

save配置 这里是用来配置触发 Redis的 RDB 持久化条件,也就是什么时候将内存中的数据保存到硬盘。比如“save m n”。表示m秒内数据集存在n次

修改时,自动触发bgsave。

2)、优点:

>由于 RDB 文件是一个非常紧凑的二进制文件,所以加载的速度会快于 AOF 方式;

>fork 子进程方式,除了fork线程阶段,其他时候不会阻塞;

>RDB 文件代表着 Redis 服务器的某一个时刻的全量数据,所以它非常适合做冷备份和全量复制的场景;

3)、缺点:

>没办法做到实时持久化,会存在丢数据的风险。定时执行持久化过程,如果在这个过程中服务器崩溃了,则会导致这段时间的数据全部丢失。

第二种:AOF,即 append only file,它是将每一行对 Redis 数据进行修改的命令以独立日志的方式存储起来。由于 Redis 是将“操作 + 数据” 以格式化的方式保存在日志文件中,他代表了这段时间所有对 Red

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值