答:Nested-Loop:选取(mysql自动优化选择)一个表作为驱动表,循环驱动表结果集,查询下一个表的数据,然后合并结果集。如果是多表join,则将前一次合并的结果作为循环数据,查询下一个表。
Block-Nested-Loop(默认开启):在NL算法的基础上,将外层循环的结果缓存起来,内层循环一次比较多条数据,减少总循环次数。比如,外层查询有100条结果,缓存10条,每次内层循环比较10条数据,则只需要循环10次。
优化:
使用小结果集作为驱动表,减少总循环次数(自动优化)
优先优化内层查询,减少每一次循环的时间
关联查询条件建立索引
设置适当的join_buffer_size,当join_buffer_size大于外层结果集时,再增大join_buffer_size不会变得更快
答:mysql使用B+Tree(平衡多路查找树)作为索引的数据结构,而innoDB和MyIsAm对索引的实现方式略有不同。使用B+Tree而不使用平衡二叉树、红黑树等结构的原因和计算机物理结构有关。索引本身需要存储,而索引一般比较大,因此索引往往存在磁盘中。而磁盘IO效率非常低,所以判断索引结构好坏的一个重要指标就是磁盘IO次数。计算机为提高磁盘IO效率,在读取数据时会进行预读,预读的大小为页的整数倍。数据库系统将B+Tree结点的大小刚好设置为一页的大小,因此一次IO就能完全载入一个结点。因为B+Tree的一个结点中会存储多个关键字,所以B+Tree的高度相比其他几种树会低很多,IO次数也会少很多。
MyIsAm索引:索引文件与数据文件是分离的。索引的叶子结点存储数据行的地址。因为相邻的叶子节点分配的物理地址并不一定相邻,所以这种索引是非聚簇索引。
InnoDB的主键索引:数据文件就是索引文件。索引的叶子结点存储完整的数据记录。逻辑相邻的数据行在物理上的存储也是相邻的,属于聚簇索引。若没有定义主键,则mysql选取第一个唯一非空的索引作为聚簇索引。若也没有唯一非空的索引,则会创建一个隐藏的聚簇索引。建表时最好使用无意义的自增列作为主键,每次插入数据只需要按顺序往后排即可。如果主键不是自增的,插入新结点时可能导致结点分裂(一个结点保存的数据记录超过一定大小就会分裂),进而导致后序其他的结点分裂,在数据量大的时候,效率非常低下。
InnoDB的普通索引:叶子结点存储主键值,普通索引的顺序与主键索引不一定一样,所以是非聚簇索引。
答:索引的选择性=不重复的值得个数/总记录数,取值范围为(0,1]。索引的选择性越小,使用索引的效果越不明显(越接近全表扫描)。极端情况下,假设只有一种不重复的值,使用索引(需要扫描整个B+Tree或hash值查出的记录为所有记录)和全表扫描完全一样。
答:
hash索引只能用于=、in和!=的查询,不能用于范围查询,不能用于排序。因为hash索引通过查找hash值一样的数据来进行索引,而hash之前的值大小与hash值大小不一定存在对应关系。
对于组合索引,不能利用前面的一个或多个索引查询
hash存在冲突的情况,因此查到一个hash值之后,还需要在多个数据记录之间选择
除上述情况外,hash索引效率远高于B+Tree
答:mvcc只有在Read Commited和Repeatable Read隔离级别下有效。在Read Uncommited下,每次读都是当前读(读最新行,而不是符合系统版本号的行),在Sirializable级别下,所有读都加锁,因此这两种级别不适用mvcc。在InnoDB的mvcc是通过在每行记录后面保存两个隐藏的列来实现的。这两个列一个保存了行的创建时系统版本号,一个保存了行的删除时系统版本号。每开始一个新事务,系统版本号都会递增。事务开始时的系统版本号就是事务版本号。下面是crud的mvcc实现(注:在事务a、b并发执行的情况下,假设事务a读取行,事务b插入(更新、删除)行。若事务b先执行,则会锁行,事务a会等b执行完之后读取最新结果,这种情况与mvcc机制无关。若事务a先执行,b是插入操作时,b的版本号大于a,a不能查到新增的行;b是更新操作时,新增的行版本号大于a,读到的仍是原始行;b是删除操作时,删除版本号大于a的版本号,仍能查到b删除的这行。以上情况无论b是否已经提交都成立,这样就解决了快照读下的脏读、不可重复读以及幻读):
select:只有符合以下两个条件的记录才会作为返回结果
行的创建版本号小于或等于事务版本号。这可以确保事务读取的行,要么是事务开始前已经存在的,要么是事务自身插入或者修改过得。。
行的删除版本要么未定义,要么大于当前事务版本号。这可以确保事务读到的行,在事务开始之前未被删除。
insert:新插入的每一行保存当前系统版本号作为行版本号。
delete:删除的每一行保存当前系统版本号作为行删除版本号。
update:插入一条新纪录,保存当前系统版本号作为行版本号,同时保存当前系统版本号作为原来的行的删除版本号。
答:死锁产生的原因是不同的事务获取锁的顺序相反(不一定非要多条sql语句才会形成死锁,如果两个事务分别通过两个非主键索引更新数据,这两个索引对应的主键顺序刚好相反时就形成了死锁。例如事务A执行update t set name="123"where age>10,事务B执行delete from t where id=1。这时假如A的结果集对应的id是(2,4,1,3,5),事务B的结果集是(1,2,3,4,5),则可能死锁)。常见的避免死锁的方法有:
尽量以相同的顺序访问表,若某两个事务因使用不同的非主键索引引起死锁,可以尝试拆分sql语句,通过非主键索引查出主键,再用主键更新记录。
尝试升级锁定的颗粒度,通过表锁减少死锁的概率
答:SynchronizedList和Vector属于同步容器,所有方法均加锁,并发性能很差。而CopyOnWriteArrayList只对写操作加锁,修改操作并不直接修改原始数组的内容,而是创建一个新数组并把原数组的引用指向新数组。由于该数组引用是volatile的并且更新和添加操作直接替换引用,因此不需要对读加锁。CopyOnWriteArrayList体现了读写分离的思想,对于并发读取的性能远高于SynchronizedList。CopyOnWriteArrayList没加读锁,因此获取到的数据不能保证实时一致,比如正在执行add操作,但还没有执行到数组赋值的那一行,则读到的还是add之前的数据。另外,CopyOnWriteArrayList占用内存较多,只有在遍历、获取操作远多于写操作是才考虑使用。SynchronizedList无法在遍历时修改(可以使用iterator的方法修改,但需要额外的同步处理),而CopyOnWriteArrayList可以(但不能通过iterator方法修改,其iterator没有提供相应的方法),但遍历时不会获取到修改的部分(遍历的是那一刻的数组副本)。
答:HashMap的结构是一个链表(或红黑树)数组,不同的Node根据hash值散列在table数组中,hash值相同的Node组成一个链表(或红黑树)。table.length>64并且链表长度>8时,会将链表结构转化成红黑树,以此来提升hash值相同时的查找效率。当table.length>threshold(容量*负载因子),或者table.length<=64并且链表长度>8时,会发生扩容,每次扩容之后的容量都是2的k次幂(左移一位)。Node的hash值对table.length取模就可以得到Node在table中的下标,但取模运算%是非常耗时的。我们把table.length记为n,当n=2^k(2的k次幂)时满足下列等式:hash%2^k=hash&(2^k-1)=hash&(n-1),因此将table.length设置为2的k次幂即可把低效的取模运算转化成高效的位运算。
以上就是极悦小编介绍的"Java工程师面试题汇总",希望对大家有帮助,如有疑问,请在线咨询,有专业老师随时为您服务。
你适合学Java吗?4大专业测评方法
代码逻辑 吸收能力 技术学习能力 综合素质
先测评确定适合在学习