【Java】高频面试题
1. B树和B+树的区别
- 结构差异:
- B树:所有节点都存储数据,非叶子节点也包含键值和数据指针。
- B+树:只有叶子节点存储数据,非叶子节点仅作为索引(键值+指针)。叶子节点通过链表连接。
- 查询效率:
- B树可能在非叶子节点命中数据,查询不稳定。
- B+树必须查找到叶子节点,查询路径长度一致,适合范围查询(链表支持顺序遍历)。
- 存储空间:
- B+树非叶子节点更小,可以缓存更多索引,减少磁盘I/O。
- 应用场景:
- B树适用于文件系统(如早期NTFS)。
- B+树是数据库索引的主流结构(如MySQL InnoDB)。
2. 聚簇索引 vs 非聚簇索引
- 聚簇索引:
- 数据存储:索引的叶子节点是数据行本身,数据按主键顺序物理存储(如InnoDB)。
- 性能:范围查询快,但插入/更新可能触发页分裂。
- 数量限制:一张表只能有一个聚簇索引。
- 非聚簇索引:
- 数据存储:叶子节点存储数据行的地址(如MyISAM)或主键(如InnoDB二级索引)。
- 性能:需要回表查询,多一次I/O。
- 数量限制:可以创建多个。
3. SQL优化思路
- 索引优化:
- 避免索引失效(如函数操作、隐式类型转换)。
- 联合索引遵循最左前缀原则。
- 查询优化:
- 减少
SELECT *
,使用覆盖索引。 - 避免子查询嵌套过深,改用
JOIN
。
- 减少
- 分库分表:
- 垂直拆分(按业务模块)、水平拆分(按数据范围或哈希)。
- 执行计划分析:
- 使用
EXPLAIN
查看是否命中索引、扫描行数等。
- 使用
- 数据库设计:
- 避免大事务、减少锁竞争,合理使用冗余字段。
4. Redis值对象与数据结构的关系
- 值对象类型对应底层数据结构:
- String:简单动态字符串(SDS)。
- List:双向链表或ziplist(压缩列表)。
- Hash:哈希表或ziplist(小数据时)。
- Set:哈希表或intset(整数集合)。
- ZSet:跳表(SkipList) + 哈希表。
- 自动优化:Redis根据数据量动态选择高效结构(如小数据用ziplist节省内存)。
5. 缓存穿透、击穿、雪崩
- 穿透(查询不存在的数据):
- 应对:布隆过滤器拦截非法请求,缓存空值。
- 击穿(热点数据过期瞬间高并发):
- 应对:互斥锁(如Redis的
SETNX
),永不过期+异步更新。
- 应对:互斥锁(如Redis的
- 雪崩(大量缓存同时失效):
- 应对:随机过期时间,集群部署保证高可用。
6. gRPC vs HTTP
- 协议层:
- gRPC基于HTTP/2(多路复用、头部压缩),HTTP API通常基于HTTP/1.1。
- 数据格式:
- gRPC使用Protobuf(二进制,高效序列化)。
- HTTP常用JSON/XML(文本,冗余高)。
- 功能特性:
- gRPC支持双向流、强类型接口定义,适合微服务间通信。
- HTTP RESTful API更通用,但对复杂场景支持较弱。
7. AOF vs RDB
- RDB:
- 机制:定时生成数据快照(二进制文件)。
- 优点:恢复快、文件小。
- 缺点:可能丢失最后一次快照后的数据。
- AOF:
- 机制:记录所有写命令(文本追加)。
- 优点:数据更安全(可配置同步频率)。
- 缺点:文件大、恢复慢。
- 混合模式(Redis 4.0+):结合两者,RDB做全量备份,AOF记录增量。
8. MySQL分表与分区表
- 分表实现:
- 水平拆分:按规则(如用户ID取模)将数据分布到多个表。
- 路由策略:应用层代码或中间件(如ShardingSphere)管理查询路由。
- 分区表:
- 内置支持:按范围(
RANGE
)、哈希(HASH
)等逻辑分区,物理存储透明。 - 应用场景:
- 历史数据归档(按时间分区)。
- 减少单个表的数据量,提升查询效率。
- 内置支持:按范围(
9. MyISAM vs InnoDB
- 核心区别:
- 事务:InnoDB支持ACID,MyISAM不支持。
- 锁粒度:InnoDB支持行锁,MyISAM仅表锁。
- 外键:InnoDB支持,MyISAM不支持。
- 其他引擎:
- Memory:数据存内存,重启丢失,适合临时表。
- Archive:高压缩比,仅支持插入/查询,适合日志存储。
10. Redis数据结构及应用场景
- String:缓存、计数器(
INCR
)。 - List:消息队列(
LPUSH/RPOP
)、时间线。 - Hash:存储对象(如用户信息)。
- Set:去重(如点赞用户)、交集/并集运算。
- ZSet:排行榜(按分数排序)、延迟队列(按时间戳排序)。
11. Redis为什么快?
- 内存操作:数据存储在内存,读写无需磁盘I/O。
- 单线程模型:避免多线程上下文切换和锁竞争。
- I/O多路复用:基于epoll/kqueue高效处理并发连接。
- 高效数据结构:如跳表(ZSet)、哈希表(快速查找)、ziplist(紧凑存储)。
以上总结涵盖了每个问题的核心要点,适合面试快速回顾。实际应用中需结合场景灵活运用。