本来约的三点的面试,但是面试官提前上线看到我在线就说提前开始吧。
MySQL
的索引为什么使用B+树而不使用跳表?
MySQL
的索引为什么使用B+树而不使用跳表?
Redis
Redis
为什么使用跳表而不使用B+树或二叉树呢?
面试官你好,我叫张三,河南人,毕业于XX大学,从XX年毕业后就一直从事java开发,差不多 3年了吧。来贵公司面试,寻求一份java开发工作。
自我介绍要说几个点:你是谁,你的优点是什么?这么多年你干了啥?在学校获得过什么奖?对哪些技术有深入研究?是否有高并发系统的设计?是否参与过什么大型项目?
总之,把你有的家底都亮出来,让人家知道你哪方面相对比较强。
这个问题其实是因人而异的,对于刚入门的朋友,叫他搭建个项目就觉得很有挑战性。
而对于大牛来说,“挑战性”已经不在是技术。更多的是何如包装项目哄好老板,如何压榨自己的下属才是项目有挑战性的点。
而在面试环节,有“挑战性”是对于面试官而言的一个标准。如果这个项目业务这个技术点面试官没接触过,听起来很难,那这个就是一个“有挑战”的项目。
如果面试官对你所说的挑战项目很熟悉,此时可能对你来说是个机会也是个挑战,回答出面试官没遇到的问题,已经如何解决的,那面试官妥妥的佩服你,反之,面试官知道的这个项目的问题,问你你答不上来,那就回面试大打折扣了。
比如说:五六年前,你的技术栈中有dubbo、Spring Boot 那是很吃香的,但是现在已经是标配了。
但是有大数据、高并发、架构改造经验的开发者还是少,因为绝大部分公司都没法发展成为大公司。但。这个也是随着软件工程怎么发展都无法改变的事。
所以对于有挑战的项目具有以下几个特点:
1、大数据量
2、高并发
3、架构改造
只要你的项目能和这几个东西沾一点边,那你的项目level就高至少一级。
这里,我给你一个回答的模板:
1、我负责的是这个xxx业务项目,这个业务的是用来xxx的。
2、前期为了快速试错,快速响应市场,前期使用了简单的xxxx方案。
3、随着业务的发展,这个方案在xxx方面出现xxx的技术问题。
4、为了解决这些技术难点,最终用了xxx方案,然后介绍这些方案,同时这些方案是怎么解决这些技术问题的。
就如实的说自己的学习历程,但要注意,学习要体现出自己是主动的,另外,标注自己有个好习惯:记笔记,好几下不如烂笔头。
推荐看官网,看书,看视频。
学习过程中,不断实践,不断反思,不断总结。
接口>抽象类>实现类
。
我们可以从五个方面来回答:
线程是否安全:HashMap 是非线程安全的, HashTable 是线程安全的。因为 HashTable 内部的方法基本都经过 synchronized 修饰。(如果你要保证线程安全的话就使用 ConcurrentHashMap);
效率:因为线程安全的问题, HashMap 要比 HashTable 效率高一点。另外, HashTable基本被淘汰,不要在代码中使用它;
对 Null key 和 Null value 的支持:HashMap 可以存储 null 的 key 和 value,但 null 作为键只能有一个,null 作为值可以有多个;HashTable 不允许有 null 键和 null 值,否则会抛出NullPointerException 。
初始容量带下和每次扩充容量大小的不同 :
① 创建时如果不指定容量初始值, Hashtable默认的初始大小为 11,之后每次扩充,容量变为原来的 2n+1。HashMap 默认的初始化大小为 16。之后每次扩充,容量变为原来的 2 倍。
② 创建时如果给定了容量初始值,那么Hashtable 会直接使用你给定的大小,而 HashMap 会将其扩充为 2 的幂次方大小( HashMap 中的tableSizeFor()
方法保证)。tableSizeFor()
方法保证)。
底层数据结构:JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)(将链表转换成红黑树前会判断,如果当前数组的长度度大于 64,那么会选择先进行数组扩容,而不是转换为红黑树)时,将链表转化为红黑树,以减少搜索时间。Hashtable 没有这样的机制。
尽管是普通不能再普通的面试题了,可面试中,照样很大部分人同学回答的不好。回答中提到了2的n次幂,面试官很有可能会继续追问相关的问题,如果还不清楚的,建议对HashMap进行系统的学习。
我的博客上之前发过两篇文章:
HashMap
添加一个元素的流程HashMap
尽管是普通不能再普通的面试题了,可面试中,照样很大部分人同学回答的不好。回答中提到了2的n次幂,面试官很有可能会继续追问相关的问题,如果还不清楚的,建议对HashMap进行系统的学习。
我的博客上之前发过两篇文章:
HashMap
添加一个元素的流程HashMap
在put添加元素过程可以分为下面9个步骤:
putVal()
方法
可以看看我博客上的博文:三年必备HashMap源码:http://www.woaijava.cc/blog/211
红黑树(Red Black Tree)是一种特化的AVL树(平衡二叉树),都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。
红黑树的特点有5个:
结点是红色或黑色。
根结点是黑色。
所有叶子都是黑色(叶子是NIL结点)
每个红色结点的两个子结点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色结点)
从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点。
其实这个问题不难,难得是可能有的面试官会问红黑树的操作,左旋转右旋转...,我面试过几百人,能说出来寥寥无几。
B+树的特点有两个:
B+树一般是1道3层。
InnoDB页的大小默认是16KB:
16KB/(4B+6B)≈1638
个索引
16KB/(4B+6B)≈1638
个索引
所以,两层的B+树可以存储:16*1638=26208
条数据;三层的B+树可以存储:16*1638*1638=42928704
条数据。
MySQL
的索引为什么使用B+树而不使用跳表?B+树是多叉树结构,每个结点都是一个16k的数据页,能存放较多索引信息,所以扇出很高。三层左右就可以存储2kw
16*1638=26208
条数据;三层的B+树可以存储:
16*1638*1638=42928704
条数据。
MySQL
的索引为什么使用B+树而不使用跳表?B+树是多叉树结构,每个结点都是一个16k的数据页,能存放较多索引信息,所以扇出很高。三层左右就可以存储
2kw
左右的数据。也就是说查询一次数据,如果这些数据页都在磁盘里,那么最多需要查询三次磁盘IO。
跳表是链表结构,一条数据一个结点,如果最底层要存放2kw
数据,且每次查询都要能达到2kw
数据,且每次查询都要能达到二分查找的效果,2kw
大概在2的24次方
左右,所以,跳表大概高度在24层左右。最坏情况下,这24层数据会分散在不同的数据页里,也即是查一次数据会经历24次磁盘IO。
因此存放同样量级的数据,B+树的高度比跳表的要少,如果放在MySQL数据库上来说,就是磁盘IO次数更少,因此B+树查询更快。
而针对写操作,B+树需要拆分合并索引数据页,跳表则独立插入,并根据随机函数确定层数,没有旋转和维持平衡的开销,因此跳表的写入性能会比B+树要好。
其实,MySQL的存储引擎是可以换的,以前mysql 5.5是myisam
,后来才有的innodb
,它们底层索引用的都是B+树。也就是说,你完全可以造一个索引为跳表的存储引擎装到MySQL里。事实上,facebook
造了个rocksDB
的存储引擎,里面就用了跳表。直接说结论,它的写入性能确实是比innodb要好,但读性能确实比innodb要差不少。感兴趣的话,可以在文章最后面的参考资料里看到他们的性能对比数据。
Redis
二分查找 24层24次磁盘IO
。因此存放同样量级的数据,B+树的高度比跳表的要少,如果放在MySQL数据库上来说,就是磁盘IO次数更少,因此B+树查询更快。而针对写操作,B+树需要拆分合并索引数据页,跳表则独立插入,并根据随机函数确定层数,没有旋转和维持平衡的开销,因此跳表的写入性能会比B+树要好。其实,MySQL的存储引擎是可以换的,以前mysql 5.5是myisam
,后来才有的
innodb
,它们底层索引用的都是B+树。也就是说,你完全可以造一个索引为跳表的存储引擎装到MySQL里。事实上,
facebook
造了个
rocksDB
的存储引擎,里面就用了跳表。直接说结论,它的写入性能确实是比innodb要好,但读性能确实比innodb要差不少。感兴趣的话,可以在文章最后面的参考资料里看到他们的性能对比数据。
Redis
为什么使用跳表而不使用B+树或二叉树呢?因为B+树的原理是 叶子节点存储数据,非叶子节点存储索引,B+树的每个节点可以存储多个关键字,它将节点大小设置为磁盘页的大小,充分利用了磁盘预读的功能。每次读取磁盘页时就会读取一整个节点,每个叶子节点还有指向前后节点的指针,为的是最大限度的降低磁盘的IO。因为数据在内存中读取耗费的时间是从磁盘的IO读取的百万分之一,而Redis是 内存中操作数据,不涉及IO,因此使用了跳表;这道题,也可以用在问你会哪些SQL优化的时候。
WHERE
子句中的列,或连接子句中的列,而不是出现在
SELECT
关键字后的列。
1、数据库设计和表创建时,考虑性能问题,比如:单表不要有太多字段,建议在20以内、索引并不是越多越好,要根据查询有针对性的创建,考虑在WHERE和ORDER BY命令上涉及的列建立索引,可根据EXPLAIN来查看是否用了索引还是全表扫描、选择合适的数据类型、选择合适索引类型等。
2、SQL编写时需要注意,比如:列表数据不要拿全表,要使用LIMIT来分页,每页数量也不要太大、可通过开启慢查询日志来找出较慢的SQL、避免select *,将需要查找的字段列出来等。
3,存储引擎选择,MyISAM适合SELECT密集型的表,而InnoDB适合INSERT和UPDATE密集型的表。
4、分库分表,比如:分库把一个数据库分成多个,建议做个读写分离就行了,真正的做分库也会带来大量的开发成本,得不偿失!不推荐使用、分表就是把一张大表,按照如上过程都优化了,还是查询卡死,那就把这个表分成多张表,把一次查询分成多次查询,然后把结果组合返回给用户。分表分为垂直拆分和水平拆分,通常以某个字段做拆分项。比如以id字段拆分为100张表:表名为 tableName_id%100。但:分表需要修改源程序代码,会给开发带来大量工作,极大的增加了开发成本,故:只适合在开发初期就考虑到了大量数据存在,做好了分表处理,不适合应用上线了再做修改,成本太高等。
5、硬件升级,这办法是最简单的,相对的成本也高,老板就不愿意了。
6、数据库升级,比如:把MySQL数据库换成大数据引擎处理数据、换成阿里云POLARDB,POLARDB 是阿里云自研的下一代关系型分布式云原生数据库,100%兼容MySQL,存储容量最高可达 100T,性能最高提升至 MySQL 的 6 倍。
方法一:如果 a 表 tid 是自增长,并且是连续的,b表的id为索引。SQL语句如下。
select * from a,b where a.tid = b.id and a.tid>500000 limit 200;
方法二:如果 a 表的 tid 不是连续的,那么就需要使用覆盖索引,tid 要么是主键,要么是辅助索引,b 表 id 也需要有索引。SQL语句如下。
select * from b, (select tid from a limit 50000,200) a where b.id = a.tid;
JVM内存结构有:程序计数器 、堆内存 、 方法区 和 栈 (java虚拟机栈和本地方法栈)。
程序计数器(Program Counter Register)是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里(仅是概念模型,各种虚拟机可能会通过一些更高效的方式去实现),字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
堆内存是JVM中最大的一块由年轻代和老年代组成,而年轻代内存又被分成三部分, Eden空间 、 From Survivor空间 、 To Survivor空间 ,默认情况下年轻代按照8:1:1
的比例来分配;
方法区存储类信息、常量、静态变量等数据,是线程共享的区域,为与Java堆区分,方法区还有一个别名Non-Heap(非堆);栈又分为java虚拟机栈和本地方法栈主要用于方法的执行。方法区可理解为一种规范,其实现比如永久代、元空间。
Java虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。虚拟机规范中对本地方法栈中的方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。
如果没有Survivor,Eden区每进行一次Minor GC ,并且没有年龄限制的话, 存活的对象就会被送到老年代。这样一来,老年代很快被填满,触发Major GC(因为Major GC一般伴随着Minor GC,也可以看做触发了Full GC)。老年代的内存空间远大于新生代,进行一次Full GC消耗的时间比Minor GC长得多。
面试官可能会问:执行时间长有什么坏处?
频发的Full GC消耗的时间很长,会影响大型程序的执行和响应速度。
假如增加老年代空间,更多存活对象才能填满老年代。虽然降低Full GC频率,但是随着老年代空间加大,一旦发生Full GC,执行所需要的时间更长。
假如减少老年代空间,虽然Full GC所需时间减少,但是老年代很快被存活对象填满,Full GC频率增加。
所以Survivor的存在意义,就是减少被送到老年代的对象,进而减少Full GC的发生,Survivor的预筛选保证,只有经历16 次Minor GC还能在新生代中存活的对象,才会被送到老年代。
这问题有的面试官是礼貌性的问,也不是很注意你回答什么,因为此时估计面试就是凉凉啦。
但是,有反问的机会,大部分还是觉得你不错,被录取的概率非常大,所以还是得慎重回答
不管ta是怎么样的心态,咱们表现好自己就行。
这个问题看上去可有可无,其实很关键,一般面试官不喜欢说“没问题”的人,因为其很注重员工的个性和创新能力。企业不喜欢求职者问个人福利之类的问题,如果有人这样问:贵公司对新入公司的员工有没有什么培训项目,我可以参加吗?或者说贵公司的晋升机制是什么样的?企业将很欢迎,因为体现出你对学习的热情和对公司的忠诚度以及你的上进心。
以上是顺丰科技面试的详细内容。更多信息请关注PHP中文网其他相关文章!