跳转到内容

实在智能一面

💡

实在智能是一家专注于AI+RPA(机器人流程自动化)的科技公司。本次一面为技术面,考察范围包括:项目经验、Java基础(集合类源码)、MySQL索引原理、SQL调优、并发编程。整体面试强度中等偏上,注重底层原理理解。


一、面试全流程(20题)

第1题:自我介绍

常规开场,简要介绍教育背景、技术栈、实习经历。


第2题:实习期间做的业务,详细聊了一下

📌

面试官深挖实习经历中的业务细节,考察对所做项目的理解深度和参与度。


第3题:爬虫怎么做的?接口有没有频率限制?爬取数据需要动态更新?

📝

考察点:反爬策略应对(IP代理池、User-Agent轮换、请求频率控制)、数据一致性(增量更新 vs 全量更新、时间戳/版本号控制)、去重策略。


二、线上排查(Arthas)

第4题:Arthas线上排查经历

💡

面经提示:这个点被包装在简历中但实际技术深度不够,面试官深入追问时露馅了。简历内容务必确保自己能讲透。

📝

Arthas常用场景:线上CPU飙高(thread -n 查看busy线程)、死锁排查(thread -b)、方法耗时监控(trace/watch/monitor)、热修复(redefine)、堆dump分析(memory/heapdump)。


三、HashMap 与 ConcurrentHashMap 深度拷打

第5题:HashMap key和value可以为null吗?ConcurrentHashMap呢?

HashMap

ConcurrentHashMap

Key为null

✅ 允许(key=null固定存在table[0]位置)

❌ 不允许,抛出NullPointerException

Value为null

✅ 允许

❌ 不允许,抛出NullPointerException

第6题:ConcurrentHashMap底层为什么不能存null值?(从并发角度考虑)

这是面试中最具深度的问题之一,面试官引导候选人从多线程二义性角度思考。

  • 核心原因:多线程二义性(Ambiguity)。get(key)返回null有两种情况:key不存在,或者key对应的value就是null。在并发环境下,无法区分两者
  • HashMap单线程下:可以containsKey(key)再get,判断到底是哪种情况。但ConcurrentHashMap中,get和containsKey不是原子操作,中间可能被其他线程修改
  • 设计哲学:Doug Lea明确设计ConcurrentHashMap不允许存null,是为了避免并发环境下null值的语义歧义,这是一种宁可抛异常也不隐藏bug的设计选择
  • 扩展:如果允许存null,那像computeIfAbsent这类原子操作就难以实现(无法区分"值不存在需要计算"和"值存在但为null")

第7题:ConcurrentHashMap底层原理

📝

JDK7:分段锁(Segment extends ReentrantLock),默认16段,每个Segment是一个小HashEntry数组。

JDK8:彻底抛弃分段锁,改为CAS + synchronized锁桶头节点。

  • put:桶为空 → CAS自旋写入;桶非空 → synchronized锁头节点 → 遍历链表/红黑树 → 插入/更新
  • get:无锁,volatile保证Node.val和Node.next的可见性
  • size:不维护全局size,通过baseCount + CounterCell[]分散计数,sumCount汇总
  • 扩容:多线程协助扩容,transferIndex(CAS)分配迁移区间

第8题:Vector底层,为什么是安全的?让我设计一个Vector

📝

Vector线程安全原理:所有public方法都用synchronized修饰(全方法锁),同一时刻只有一个线程能操作。缺点是高并发下性能极差。

设计一个线程安全的List思路:

  • 读写分离:CopyOnWriteArrayList(读无锁,写加锁复制)→ 适合读多写极少
  • 分段锁:类似JDK7 ConcurrentHashMap思路,把List分成多段分别加锁
  • CAS无锁:类似ConcurrentLinkedQueue,通过CAS+自旋实现原子操作

第9题:HashSet的实现

📝

HashSet基于HashMap实现。元素作为key存入HashMap,value统一使用一个叫PRESENT的Object常量。add(key) → map.put(key, PRESENT);contains → map.containsKey();remove → map.remove()。所有操作委托给HashMap。


四、MySQL 索引深度拷打

第10题:MySQL索引结构,聊到B+树、哈希索引、B树

索引类型

特点

适用场景

B+树

数据全在叶子节点,叶子节点双向链表连接。非叶子节点只存索引

范围查询、排序、=等值查询。InnoDB唯一索引结构

哈希索引

O(1)等值查询,不支持范围查询和排序

Memory引擎、自适应哈希索引(AHI)

B树

每个节点都存数据,叶子节点无链表

MongoDB等非关系型数据库使用较多

B+树胜出的原因:(1)非叶子节点不存数据 → 同一磁盘页存更多索引 → 树更矮 → IO次数更少 (2)叶子节点有双向链表 → 范围查询/排序只需遍历叶子链表 (3)查询性能稳定,每次查询IO次数=树的高度

第11题:三层B+树存多少数据(两千万)怎么计算的?

这是经典计算题,面试官纠正了候选人的计算错误。

第12题:主键索引和联合索引的区别?

主键索引(聚簇索引)

联合索引(二级索引)

存储

叶子节点存完整行数据

叶子节点存索引列+主键值

数量

每表只有一个

可以有多个

回表

不需要(数据就在叶子节点)

非覆盖查询需要回表

排序

物理存储按主键排序

按联合索引定义顺序排序

第13题:回表查询 + 索引下推

📌

回表:二级索引叶子节点只存主键值,查询的列不全在索引中时,需用主键回到聚簇索引查完整行数据 — 这是额外的一次IO。

索引下推(ICP, Index Condition Pushdown,MySQL 5.6+):将部分WHERE条件下推到存储引擎层,在索引层面就过滤数据,减少回表次数。

第14题:7-8个字段排序取最大一行,高并发下如何优化?

需求:对表中7-8个字段进行排序,获取最大的一行数据。高并发请求量巨大。

📝

问题分析:每次请求都ORDER BY多列 → filesort → 大量临时表 → 高并发下数据库压力巨大。尤其是ORDER BY 7-8个字段,排序代价极高。

优化方案

  1. 预计算字段:在表中增加一个computed_score列,将7-8个字段的排序逻辑提前计算好(通过应用层或触发器),最终只需要 ORDER BY computed_score DESC LIMIT 1
  2. 建立联合索引:ORDER BY的所有字段建联合索引(列顺序与ORDER BY一致)。顺序——先等值查询字段,再排序字段(充分利用索引有序性避免filesort)
  3. Redis缓存:定时任务(如每5分钟)计算TOP 1并写入Redis,请求直接读缓存。适合时效性要求不高的场景
  4. 异步维护:写操作时异步更新排行榜(如维护一个小顶堆/优先队列,保留TOP N),读请求直接返回缓存结果

第15题:合并的思路

(面试官引导思考如何用合并的思路进一步优化排序查询)


第16题:MVCC

📝

MVCC(多版本并发控制)是InnoDB实现高并发事务的核心机制。

  • 核心字段:每行记录有DB_TRX_ID(最近修改的事务ID)、DB_ROLL_PTR(回滚指针,指向undo log)、DB_ROW_ID(行ID)
  • Read View:快照读时生成,包含当前活跃事务列表。根据可见性规则判断每行数据的哪个版本对当前事务可见
  • 可见性判断:版本trx_id = 当前事务 → 可见;trx_id < min_trx_id → 可见(已提交);trx_id > max_trx_id → 不可见(未来事务);中间 → 看是否在活跃列表中
  • RC vs RR:RC级别每次快照读生成新Read View;RR级别事务中第一次读生成Read View,后续复用
  • undo log链:通过回滚指针串起来,形成版本链,Read View沿版本链找第一个可见版本

五、SQL调优 + 索引失效拷打

第17题:SQL调优,详细说了SQL调优的内容

📝

(候选人详细阐述SQL调优方法论)

  • 索引优化:建立合理索引、联合索引、覆盖索引
  • SQL改写:避免SELECT *、JOIN代替子查询、UNION ALL代替UNION
  • 深度分页:游标分页、子查询优化、延迟关联
  • EXPLAIN分析:关注type/rows/Extra

第18题:索引失效的拷打

失效场景

原因

左模糊LIKE '%xx'

破坏B+树有序性,无法利用索引

索引列计算/函数

WHERE YEAR(create_time)=2025 需对每行先计算再比较

隐式类型转换

VARCHAR列用数字查询,MySQL需逐行隐式转换

OR连接无索引列

OR一侧无索引 → 全表扫描

违背最左前缀

联合索引(a,b,c),WHERE b=1 AND c=2 不走索引(缺少a)

范围查询后的列

索引(a,b,c),WHERE a=1 AND b>5 AND c=3 → c不走索引

第19题:最左匹配原则,联合索引是否走索引

📝

最左前缀原则:联合索引(a,b,c)相当于创建了(a)、(a,b)、(a,b,c)三个索引。查询条件必须从最左列开始且不能跳过中间列。

  • WHERE a=1 ✅ 走索引(匹配a)
  • WHERE a=1 AND b=2 ✅ 走索引(匹配a,b)
  • WHERE a=1 AND b=2 AND c=3 ✅ 走索引(匹配a,b,c)
  • WHERE b=2 ❌ 不走(缺少a)
  • WHERE a=1 AND c=3 ⚠️ 只走a(b缺失,c不能跳过b使用索引)
  • WHERE a=1 AND b>5 AND c=3 ⚠️ 只走a,b(c在范围查询之后不走)

六、开发素养

第20题:如何去做一个任务的需求

📝

考察点:软件开发流程、需求理解能力、方案设计思维。

  • 需求分析:理解需求背景和要解决的问题(Why),明确功能范围和边界条件
  • 技术方案:评估技术选型 → 数据库表设计 → 接口设计 → 画流程图/时序图
  • 方案评审:组内Review,识别风险点、性能瓶颈、安全漏洞
  • 开发排期:任务拆分(WBS)→ 工时评估 → 里程碑设定
  • 开发实现:核心逻辑单元测试 → 完整功能开发 → 自测(边界/异常)
  • 联调测试:接口对接 → 集成测试 → 性能压测(必要时)
  • 上线与监控:灰度发布 → 日志监控 → 回滚预案

面试总结:本次一面技术深度整体较高,ConcurrentHashMap底层原理和不能存null的并发语义是核心难点;MySQL索引(B+树数据量计算、回表、ICP、最左前缀)是绝对高频考点;SQL调优和索引失效是必备基本功。教训:Arthas这类简历上写的技术点必须能讲透,否则是减分项。