24 个必须掌握的数据库⾯试题

Posted 小坏蛋至尊宝

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了24 个必须掌握的数据库⾯试题相关的知识,希望对你有一定的参考价值。

⼀、为什么⽤⾃增列作为主键
1、如果我们定义了主键(PRIMARY KEY),那么InnoDB会选择主键作为聚集索引。
如果没有显式定义主键,则InnoDB会选择第⼀个不包含有NULL值的唯⼀索引作为主键索引。
如果也没有这样的唯⼀索引,则InnoDB会选择内置6字节⻓的ROWID作为隐含的聚集索引(ROWID随着⾏记录的写⼊⽽主键递
增,这个ROWID不像ORACLE的ROWID那样可引⽤,是隐含的)。
2、数据记录本⾝被存于主索引(⼀颗B+Tree)的叶⼦节点上,这就要求同⼀个叶⼦节点内(⼤⼩为⼀个内存⻚或磁盘⻚)的各
条数据记录按主键顺序存放
因此每当有⼀条新的记录插⼊时,mysql会根据其主键将其插⼊适当的节点和位置,如果⻚⾯达到装载因⼦(InnoDB默认为
15/16),则开辟⼀个新的⻚(节点)
3、如果表使⽤⾃增主键,那么每次插⼊新的记录,记录就会顺序添加到当前索引节点的后续位置,当⼀⻚写满,就会⾃动开辟
⼀个新的⻚
4、如果使⽤⾮⾃增主键(如果⾝份证号或学号等),由于每次插⼊主键的值近似于随机,因此每次新纪录都要被插到现有索引
⻚得中间某个位置
此时MySQL不得不为了将新记录插到合适位置⽽移动数据,甚⾄⽬标⻚⾯可能已经被回写到磁盘上⽽从缓存中清掉,此时⼜要从
磁盘上读回来,这增加了很多开销
同时频繁的移动、分⻚操作造成了⼤量的碎⽚,得到了不够紧凑的索引结构,后续不得不通过OPTIMIZE TABLE来重建表并优化
填充⻚⾯。
⼆、为什么使⽤数据索引能提⾼效率
数据索引的存储是有序的
在有序的情况下,通过索引查询⼀个数据是⽆需遍历索引记录的
极端情况下,数据索引的查询效率为⼆分法查询效率,趋近于 log2(N)
三、B+树索引和哈希索引的区别
B+树是⼀个平衡的多叉树,从根节点到每个叶⼦节点的⾼度差值不超过1,⽽且同层级的节点间有指针相互链接,是有序的,如下图
在这里插入图片描述
哈希索引就是采⽤⼀定的哈希算法,把键值换算成新的哈希值,检索时不需要类似B+树那样从根节点到叶⼦节点逐级查找,只需⼀次哈希算法即可,是⽆序的,如下图所⽰:
在这里插入图片描述
四、哈希索引的优势:
等值查询,哈希索引具有绝对优势(前提是:没有⼤量重复键值,如果⼤量重复键值时,哈希索引的效率很低,因为存在所谓的
哈希碰撞问题。)
五、哈希索引不适⽤的场景:
不⽀持范围查询
不⽀持索引完成排序
不⽀持联合索引的最左前缀匹配规则
通常,B+树索引结构适⽤于绝⼤多数场景,像下⾯这种场景⽤哈希索引才更有优势:
在HEAP表中,如果存储的数据重复度很低(也就是说基数很⼤),对该列数据以等值查询为主,没有范围查询、没有排序的时
候,特别适合采⽤哈希索引,例如这种SQL:

#仅等值查询
select id, name from table where name='李明'; 

⽽常⽤的 InnoDB 引擎中默认使⽤的是B+树索引,它会实时监控表上索引的使⽤情况。
如果认为建⽴哈希索引可以提⾼查询效率,则⾃动在内存中的“⾃适应哈希索引缓冲区”建⽴哈希索引(在InnoDB中默认开启⾃
适应哈希索引)。
通过观察搜索模式,MySQL会利⽤index key的前缀建⽴哈希索引,如果⼀个表⼏乎⼤部分都在缓冲池中,那么建⽴⼀个哈希索
引能够加快等值查询。
注意:在某些⼯作负载下,通过哈希索引查找带来的性能提升远⼤于额外的监控索引搜索情况和保持这个哈希表结构所带来
的开销。
但某些时候,在负载⾼的情况下,⾃适应哈希索引中添加的read/write锁也会带来竞争,⽐如⾼并发的join操作。like操作和%的
通配符操作也不适⽤于⾃适应哈希索引,可能要关闭⾃适应哈希索引。

六、B树和B+树的区别
1、B树,每个节点都存储key和data,所有节点组成这棵树,并且叶⼦节点指针为nul,叶⼦结点不包含任何关键字信息。
在这里插入图片描述

2、B+树,所有的叶⼦结点中包含了全部关键字的信息,及指向含有这些关键字记录的指针,且叶⼦结点本⾝依关键字的⼤⼩⾃
⼩⽽⼤的顺序链接
所有的⾮终端结点可以看成是索引部分,结点中仅含有其⼦树根结点中最⼤(或最⼩)关键字。(⽽B 树的⾮终节点也包含需要查
找的有效信息)
在这里插入图片描述

七、为什么说B+⽐B树更适合实际应⽤中操作系统的⽂件索引和数据库索引?
1、B+的磁盘读写代价更低。
B+的内部结点并没有指向关键字具体信息的指针,因此其内部结点相对B树更⼩。
如果把所有同⼀内部结点的关键字存放在同⼀盘块中,那么盘块所能容纳的关键字数量也越多。⼀次性读⼊内存中的需要查找的
关键字也就越多。相对来说IO读写次数也就降低了。
2、B±tree的查询效率更加稳定。
由于⾮终结点并不是最终指向⽂件内容的结点,⽽只是叶⼦结点中关键字的索引。所以任何关键字的查找必须⾛⼀条从根结点到
叶⼦结点的路。所有关键字查询的路径⻓度相同,导致每⼀个数据的查询效率相当。
Tips:欢迎关注微信公众号:Java后端,每⽇技术博⽂推送。
⼋、MySQL联合索引
1、联合索引是两个或更多个列上的索引。
对于联合索引:Mysql从左到右的使⽤索引中的字段,⼀个查询可以只使⽤索引中的⼀部份,但只能是最左侧部分。
例如索引是key index (a,b,c). 可以⽀持a 、 a,b 、 a,b,c 3种组合进⾏查找,但不⽀持 b,c进⾏查找 .当最左侧字段是常量引⽤时,
索引就⼗分有效。
2、利⽤索引中的附加列,您可以缩⼩搜索的范围,但使⽤⼀个具有两列的索引不同于使⽤两个单独的索引。
复合索引的结构与电话簿类似,⼈名由姓和名构成,电话簿⾸先按姓⽒对进⾏排序,然后按名字对有相同姓⽒的⼈进⾏排序。
如果您知道姓,电话簿将⾮常有⽤;如果您知道姓和名,电话簿则更为有⽤,但如果您只知道名不知道姓,电话簿将没有⽤处。
九、什么情况下应不建或少建索引
1、表记录太少
2、经常插⼊、删除、修改的表
3、数据重复且分布平均的表字段,假如⼀个表有10万⾏记录,有⼀个字段A只有T和F两种值,且每个值的分布概率⼤约为50%,
那么对这种表A字段建索引⼀般不会提⾼数据库的查询速度。
4、经常和主字段⼀块查询但主字段索引值⽐较多的表字段
⼗、什么是表分区?
表分区,是指根据⼀定规则,将数据库中的⼀张表分解成多个更⼩的,容易管理的部分。从逻辑上看,只有⼀张表,但是底层却
是由多个物理分区组成。
⼗⼀、表分区与分表的区别
分表:指的是通过⼀定规则,将⼀张表分解成多张不同的表。⽐如将⽤⼾订单记录根据时间成多个表。
分表与分区的区别在于:分区从逻辑上来讲只有⼀张表,⽽分表则是将⼀张表分解成多张表。

⼗⼆、表分区有什么好处?
1、存储更多数据。分区表的数据可以分布在不同的物理设备上,从⽽⾼效地利⽤多个硬件设备。和单个磁盘或者⽂件系统相
⽐,可以存储更多数据
2、优化查询。在where语句中包含分区条件时,可以只扫描⼀个或多个分区表来提⾼查询效率;涉及sum和count语句时,也可
以在多个分区上并⾏处理,最后汇总结果。
3、分区表更容易维护。例如:想批量删除⼤量数据可以清除整个分区。
4、避免某些特殊的瓶颈,例如InnoDB的单个索引的互斥访问,ext3问价你系统的inode锁竞争等。
⼗三、分区表的限制因素
1、⼀个表最多只能有1024个分区
2、MySQL5.1中,分区表达式必须是整数,或者返回整数的表达式。在MySQL5.5中提供了⾮整数表达式分区的⽀持。
3、如果分区字段中有主键或者唯⼀索引的列,那么多有主键列和唯⼀索引列都必须包含进来。即:分区字段要么不包含主键或
者索引列,要么包含全部主键和索引列。
4、分区表中⽆法使⽤外键约束
5、MySQL的分区适⽤于⼀个表的所有数据和索引,不能只对表数据分区⽽不对索引分区,也不能只对索引分区⽽不对表分区,
也不能只对表的⼀部分数据分区。
⼗四、如何判断当前MySQL是否⽀持分区?
命令:show variables like ‘%partition%’ 运⾏结果:
在这里插入图片描述

have_partintioning 的值为YES,表⽰⽀持分区。
⼗五、MySQL⽀持的分区类型有哪些?
RANGE分区:这种模式允许将数据划分不同范围。例如可以将⼀个表通过年份划分成若⼲个分区
LIST分区:这种模式允许系统通过预定义的列表的值来对数据进⾏分割。按照List中的值分区,与RANGE的区别是,range分区
的区间范围值是连续的。
HASH分区 :这中模式允许通过对表的⼀个或多个列的Hash Key进⾏计算,最后通过这个Hash码不同数值对应的数据区域进⾏
分区。例如可以建⽴⼀个对表主键进⾏分区的表。
KEY分区 :上⾯Hash模式的⼀种延伸,这⾥的Hash Key是MySQL系统产⽣的。
⼗六、四种隔离级别
Serializable (串⾏化):可避免脏读、不可重复读、幻读的发⽣。
Repeatable read (可重复读):可避免脏读、不可重复读的发⽣。
Read committed (读已提交):可避免脏读的发⽣。
Read uncommitted (读未提交):最低级别,任何情况都⽆法保证。
⼗七、关于MVCC
MySQL InnoDB存储引擎,实现的是基于多版本的并发控制协议——MVCC (Multi-Version Concurrency Control)
注:与MVCC相对的,是基于锁的并发控制,Lock-Based Concurrency Control
MVCC最⼤的好处:读不加锁,读写不冲突。在读多写少的OLTP应⽤中,读写不冲突是⾮常重要的,极⼤的增加了系统的并发性
能,现阶段⼏乎所有的RDBMS,都⽀持了MVCC。
LBCC:Lock-Based Concurrency Control,基于锁的并发控制
MVCC:Multi-Version Concurrency Control
基于多版本的并发控制协议。纯粹基于锁的并发机制并发量低,MVCC是在基于锁的并发控制上的改进,主要是在读操作上提⾼
了并发量。
⼗⼋、在MVCC并发控制中,读操作可以分成两类:
快照读 (snapshot read):读取的是记录的可⻅版本 (有可能是历史版本),不⽤加锁(共享读锁s锁也不加,所以不会阻塞其他事
务的写)
当前读 (current read):读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条
记录
⼗九、⾏级锁定的优点:
1、当在许多线程中访问不同的⾏时只存在少量锁定冲突。
2、回滚时只有少量的更改
3、可以⻓时间锁定单⼀的⾏。
⼆⼗、⾏级锁定的缺点:
⽐⻚级或表级锁定占⽤更多的内存。
当在表的⼤部分中使⽤时,⽐⻚级或表级锁定速度慢,因为你必须获取更多的锁。
如果你在⼤部分数据上经常进⾏GROUP BY操作或者必须经常扫描整个表,⽐其它锁定明显慢很多。
⽤⾼级别锁定,通过⽀持不同的类型锁定,你也可以很容易地调节应⽤程序,因为其锁成本⼩于⾏级锁定。
⼆⼗⼀、MySQL优化
开启查询缓存,优化查询
explain你的select查询,这可以帮你分析你的查询语句或是表结构的性能瓶颈。EXPLAIN 的查询结果还会告诉你你的索引
主键被如何利⽤的,你的数据表是如何被搜索和排序的
当只要⼀⾏数据时使⽤limit 1,MySQL数据库引擎会在找到⼀条数据后停⽌搜索,⽽不是继续往后查少下⼀条符合记录的
数据
为搜索字段建索引
使⽤ ENUM ⽽不是 VARCHAR。如果你有⼀个字段,⽐如“性别”,“国家”,“⺠族”,“状态”或“部⻔”,你知道这
些字段的取值是有限⽽且固定的,那么,你应该使⽤ ENUM ⽽不是VARCHAR
Prepared
StatementsPrepared
Statements很像存储过程,是⼀种运⾏在后台的SQL语句集合,我们可以从使⽤
prepared statements 获得很多好处,⽆论是性能问题还是安全问题。
Prepared Statements 可以检查⼀些你绑定好的变量,这样可以保护你的程序不会受到“SQL注⼊式”攻击
垂直分表
选择正确的存储引擎
⼆⼗⼆、key和index的区别
key 是数据库的物理结构,它包含两层意义和作⽤,⼀是约束(偏重于约束和规范数据库的结构完整性),⼆是索引(辅助查询
⽤的)。包括primary key, unique key, foreign key 等
index是数据库的物理结构,它只是辅助查询的,它创建时会在另外的表空间(mysql中的innodb表空间)以⼀个类似⽬录的结
构存储。索引要分类的话,分为前缀索引、全⽂本索引等;
⼆⼗三、Mysql 中 MyISAM 和 InnoDB 的区别有哪些?
区别:
1、InnoDB⽀持事务,MyISAM不⽀持
对于InnoDB每⼀条SQL语⾔都默认封装成事务,⾃动提交,这样会影响速度,所以最好把多条SQL语⾔放在begin和commit之
间,组成⼀个事务;
2、InnoDB⽀持外键,⽽MyISAM不⽀持。
对⼀个包含外键的InnoDB表转为MYISAM会失败;
3、InnoDB是聚集索引,数据⽂件是和索引绑在⼀起的,必须要有主键,通过主键索引效率很⾼。
但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此主键不应该过⼤,因为主键太⼤,其他索引也都
会很⼤。
⽽MyISAM是⾮聚集索引,数据⽂件是分离的,索引保存的是数据⽂件的指针。主键索引和辅助索引是独⽴的。
4、InnoDB不保存表的具体⾏数,执⾏select count(*) from table时需要全表扫描。⽽MyISAM⽤⼀个变量保存了整个表的⾏
数,执⾏上述语句时只需要读出该变量即可,速度很快;
5、Innodb不⽀持全⽂索引,⽽MyISAM⽀持全⽂索引,查询效率上MyISAM要⾼;
如何选择:
是否要⽀持事务,如果要请选择innodb,如果不需要可以考虑MyISAM;
如果表中绝⼤多数都只是读查询,可以考虑MyISAM,如果既有读写也挺频繁,请使⽤InnoDB
系统奔溃后,MyISAM恢复起来更困难,能否接受;
MySQL5.5版本开始Innodb已经成为Mysql的默认引擎(之前是MyISAM),说明其优势是有⽬共睹的,如果你不知道⽤什
么,那就⽤InnoDB,⾄少不会差。
⼆⼗四、数据库表创建注意事项
1、字段名及字段配制合理性
剔除关系不密切的字段;
字段命名要有规则及相对应的含义(不要⼀部分英⽂,⼀部分拼⾳,还有类似a.b.c这样不明含义的字段);
字段命名尽量不要使⽤缩写(⼤多数缩写都不能明确字段含义);
字段不要⼤⼩写混⽤(想要具有可读性,多个英⽂单词可使⽤下划线形式连接);
字段名不要使⽤保留字或者关键字;
保持字段名和类型的⼀致性;
慎重选择数字类型;
-给⽂本字段留⾜余量;
2、系统特殊字段处理及建成后建议
添加删除标记(例如操作⼈、删除时间);
建⽴版本机制;
3、表结构合理性配置
多型字段的处理,就是表中是否存在字段能够分解成更⼩独⽴的⼏部分(例如:⼈可以分为男⼈和⼥⼈);
多值字段的处理,可以将表分为三张表,这样使得检索和排序更加有调理,且保证数据的完整性!
4、其它建议
对于⼤数据字段,独⽴表进⾏存储,以便影响性能(例如:简介字段);
使⽤varchar类型代替char,因为varchar会动态分配⻓度,char指定⻓度是固定的;
给表创建主键,对于没有主键的表,在查询和索引定义上有⼀定的影响;
避免表字段运⾏为null,建议设置默认值(例如:int类型设置默认值为0)在索引查询上,效率⽴显;
建⽴索引,最好建⽴在唯⼀和⾮空的字段上,建⽴太多的索引对后期插⼊、更新都存在⼀定的影响(考虑实际情况来创建);

以上是关于24 个必须掌握的数据库⾯试题的主要内容,如果未能解决你的问题,请参考以下文章

21道 Redis 常见面试题,必须掌握!

48个值得掌握的JavaScript代码片段(上)

最新腾讯等大厂c/c++后端 linux开发常见面试题汇总

C语言必会面试题(3耶稣有13个门徒,当中有一个就是出卖耶稣的叛徒,请用排除法找出这位叛徒:13人围坐一圈,从第一个開始报号:1,2,3,1,2,3...。凡是报到“3”就退出圈子,...)(代码片段

JavaScript笔试题(js高级代码片段)

在Android中将数据从基本活动发送到片段[重复]