作为面试官,我会按如下层次考核求职者数据库方面的技能。
1 问基本的操作技能,这里当然不会直接问sql语法,而会挑些点来问,比如左连接怎么做,with语句或merge语句的含义和用法。
2 问些高级技能,其中包括事务等,比如问事务隔离级别和传播机制。也包括索引,比如索引的底层,索引的数据结构和索引的种类。
以上都是比较基础的,如果是初级开发的话,能说好上面的问题就好了,如果是要面试3年及以上的高级开发,还会问如下的调优技能和分布式组件技能。
3 调优技能一般会问,在你们的项目里,一般是怎么发现慢sql,发现慢sql以后会用什么方式来排查和解决?或者问,你们设计数据库表和数据库索引的时候,一般是怎么考虑的?或者就问个开放性的问题,你们是怎么排查和解决数据库性能问题的?
4 数据库方面的组件一般包括redis缓存组件和mycat分库组件,一般会问,你们项目里有没有用过?结合一个例子告诉我怎么用?如果是面高级或资深开发时,还会深入问些,比如用到的redis是集群还是单机版?怎么做redis持久化?redis的缓存穿透问题有没有遇到过?Mycat怎么实现分库的?mycat组件上线后是怎么做数据迁移的?
在对应准备数据库方面的面试时,题好背,如果不知道怎么背题,多看看网文多参加几次面试就行,但数据库调优方面的问题,是无法回避的,比如面试官就一句,你们项目是怎么分析和排查数据库性能问题的?
在系统写调优方面的回答模版前,先说下如下回答的价值,如果初级开发(工作经验少于3年)能说好,能超越大多数的竞争者,而哪怕高级开发说好这些话,也能让面试官感觉你很资深,而对于架构师而言,这些回答是基本的标配项。下面具体说下数据库调优方面该怎么说?
1 总是先要发现待调优的sql语句,这块可以通过new relic,或zabbix或cat组件来发现,比如通过配置把这些组件连接到对应的数据库服务器上,如果出现超过阈值的慢sql,或发邮件告警。如果再不济,可以直接说,把mysql数据库配置到linux服务器上,运维人员做来配置,所以一旦出现运行时间超过10秒(或其他配置值)的sql语句,我会收到告警邮件。
这块一定要说,否则连哪些sql要优化也不知道,怎么做优化?事实上如果这块好好准备,还能说好系统监控组件这一块。
2 发现慢sql以后,首先用执行计划(sql explain)去分析下该sql语句耗时主要耗在哪块?一般耗时长的点会有,没建索引或没走索引,大表关联导致耗时长,或长sql语句里,同一个sql块被之行多次。当然还有其他可能会费时间的点,但上述点经常会遇到,也好准备。
通过执行计划分析到慢sql的原因后,就可以针对性地说解决方案。可以是建索引,但这里要注意,被建索引的表规模至少十万级,而被建索引的字段应当重复率低,否则索引建了白建,这些原因自己查,但我在面试求职者时,真听说过为几千条表规模建索引,以及为性别字段建索引的说辞。
调优要点还可以是在建表层面,比如预估一个业务点(比如商品业务)数据表规模很大,到至少十万级,那么就别再按三范式建表,因为三范式虽然不会有冗余数据,但表关联起来吃不消,遇到这种情况,可以把商品的所有字段放到一个大表,也就是用反范式来建表。但如果求职者是表设计好以后入项目组的,就别说这种话了。
调优要点还包括,用with语句把长sql里运行多次的sql块提出来,或者干脆重写sql。当然还有些说辞,比如更改mysql里关于锁的配置,或者跳低oracle的水平位,但这种话别说,因为做项目时不大可能全局性地修改mysql或oracle的配置,这样风险太大。
3 以上是单机版的调优手段,说好这块还可以说redis缓存调优,这块该怎么说呢?先准备个业务点,比如发订单,在这过程中会多次访问用户表,此时第一次访问时,就可以把数据放入缓存,然后准备下放入缓存用户数据的结构(无非是list或hash型),然后准备下java访问redis的api,应该是用Jedis或RedisTemplate。
在此基础上,可以说下解决过redis的缓存穿透问题,无非是缓存空数据或不存在的数据,同时可以说下,为了避免缓存的数据一直存在于内存,所以需要设置缓存数据的超时时间。
如果是初级开发,说到这个程度就可以了,而且还可以说是用到单机版的redis,如果是高级开发,还可以说下用了redis集群,但用的时候基本上是主从集群,向主节点写,主节点向从节点同步数据,从从节点读缓存。但别说用哨兵集群,因为现在不怎么用了,如果要说用cluster集群也行,但cluster集群单点失效方面的问题很难回答,这要自担风险,其实如果感觉不怎忙好准备,说个主从redis集群也行。
4 如果再想往深了说,可以说引入了mycat分库分表组件。这块基本的该怎么说呢?有张千万级别(至少百万级别)的大表,比如订单流水表,通过配置mycat参数,按id取模的方式,把它们分散到5个表结构一样的字表里,比如id%5是1分到1号子表,依次类推。
用了mycat前,需要排查针对该表的所有sql语句,即所有sql语句都要包含分库字段,比如id,而且不能有针对全表的操作,比如group by等,如果遇到全表操作,需要改写,或用java业务实现。
说到这种程度,就能从发现到排查的流程角度,全面地展示自己数据库调优方面的技能。而且不仅能展示单机版的调优技能,还能展示分布式组件级别的调优技能。这套话说下来,哪怕去面需要5年工作经验的高级开发,至少在数据库层面能及格,更何况去面只要3年以内的初级开发岗。
如果大家想进一步了解我的情况,可以关注我。