高频面试题——数据库

数据库

1:怎么删表

Drop:删除内容和定义,释放空间。删除整个表。

turncate:删除内容,释放空间但不删除定义。与Drop不同的是,只是清空表数据而已

Delete:用来删除表中的行。

2:数据库索引

哈希索引和B+数索引

对于哈希索引来说,底层的数据结构就是哈希表,因此在绝大多数需求为单条记录查询或等值查询的时候,可以选择哈希索引,查询性能更快;其余大部分场景建议选择B+树索引。

4:B树和B+树的区别,为什么用B+树

在使用二叉树的时候,由于二叉树的深度过大而造成IO读写过于频繁,进而导致查找效率底下,因此采用多叉树结构,B树的各种操作能够使B树能保持较低的高度。

B+树的磁盘读写代价更小,因为非叶子节点只存储key值,不存储value,在叶子节点中,值按照顺序进行存储。

B树在提高IO性能的同时并没有解决元素遍历的效率地下问题,B+树只需要区遍历叶子节点就可以实现整颗树的遍历,而且还可以实现基于范围的查找。B树不支持这样的查找。

5:聚集索引和非聚集索引

聚集索引:索引中的键值逻辑顺序决定了表中相应行的物理顺序(索引中的数据物理存放地址和索引的顺序是一致的),一个表只能有一个聚集索引。但该索引可以包含多个列(组合索引)

非聚集索引:索引的逻辑顺序和数据的物理存储顺序不同

6:为什么只能有一个聚集索引

因为聚集索引代表了表的物理顺序,一个表只能有一个物理排序顺序,所以只能有一个聚集索引

7:主键自增有什么好处

1):数据库自动编号,速度快,按顺序存放,对于检索非常有利

2):数据型,占用空间小

3):不用担心主键重复的问题

4):自增的话可以防止页分裂

8:索引太多的坏处

1):随着数据的增删改,也需要动态的维护索引

2):索引需要物理空间来存储

3):随着数据的越来越大,索引的性能会下降

9:什么时候推荐创建索引

1):主键自动创建唯一索引

2):频发作为查询条件的字段应该创建索引

3):查询中与其他表关联的字段,外键应该创建索引

4):组合索引性价比更高

10:最左匹配原则

当存在组合索引时,执行一个sql语句,以最左边为起点,一直向右进行匹配,直到遇到范围匹配为止。

索引的底层是一颗B+树,联合索引也是一颗B+树,只不过联合索引的键值数量不是一个,而是多个。例如,在底层,联合索引首先是按a排序的,b是无序的,在a相等的情况下,b是按顺序排序的,但是这种顺序是相对的。所以最左匹配原则遇上范围查询就会停止,剩下的字段都无法使用索引。

11:varchar和char的区别

1):char是固定的,varchar是不固定的

2):char的存储方式是:对英文字符ASCII占用1字节,对一个汉字占用两个字节

        varchar:对英文和中文都是占用2字节

3):两者的存储数据都是非unicode的字符数据。

12:存储引擎的区别

是否支持行级锁

是否支持事务

是否支持崩溃后的安全恢复

是否支持外键

是否支持MVCC

13:InnoDB的主键索引与非主键索引的区别

非主键索引的叶子节点存放的是主键的值,而主键索引的叶子节点存放的是整行数据,其中非主键索引页被称为二级索引,而主键索引也被称为聚集索引。当我们进行查询的时候,先从非主键索引处找到主键的值,然后再到主键表中进行数据的查询,这个过程叫做回表。

因为基于非主键索引的查询需要多扫描一颗索引树,所以主键索引的效率更高。

14:索引失效

1):like是以%开头的查询语句,模糊匹配查询

2):使用多列索引的查询语句

3):使用OR关键字查询语句

4):如果类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不适用索引。

5):当全表扫描比索引速度快的时候,使用全表扫描

15:索引的类型

唯一索引

主键索引

默认索引

16:使用索引应该注意的事项

1):不要使用or

2):慎用前导模糊匹配

3):删除长期不使用的索引

4):不宜创建过多的索引,最好使用组合索引

17:InnoDB索引存储结构

B+树

18:B+树的查找时间复杂度是多少

层数为log(m)n,每一层平均m/2,所以以共是(m/2)log(m)n,由于m是常数,所以复杂度为logn

19:事务的ACID,一致性中,如何理解DB的完整性约束?

完整性:存储在数据库中的所有数据值均正确的状态。

完整性约束分为:

   1):实体完整性约束(主键约束)

   2):域完整性(对数据表中字段属性的约束)

   3):参考完整性(建立关联关系的数据表间数据参照引用的约束,对外键的约束)

   4):用户定义完整性。

20:事务的并发会产生什么问题

1):脏读:事务A读取了事务B未提交的数据。

2):不可重复读:事务A多次读取同一数据,事务B在事务A多次读取的过程中,对数据做了更新并提交,导致事务A多次读取同一数据时,结果会不一致

3):幻读:幻读与不可重复读类似,它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据,在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样。

不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需要锁住满足条件的行,解决幻读还需要锁表。

20:事务的隔离级别,默认为RR,为什么

读未提交:允许读取未提交的数据变更,可能会导致脏读,幻读或不可重复读。

读提交RC:允许读取并发事务已经提交的数据,可以阻止脏读但是幻读和不可重复读仍有可能发生

可重复读:(RR)next-key lock:对同一字段的多次读取结果都是一致的。

串行化:最高的隔离级别,完全服从ACID的隔离级别。



默认是RR,因为在主从结构中,是基于binlog来进行同步的,binlog的默认级别为statement,这种级别在RC隔离级别下会出现bug,RR级别下,binlog为任何格式均不会造成主从数据的不一致。

为什么会出现主从不一致:说简单就是再master上执行的顺序是先删除后插入,而此时binlog为statement,它记录的顺序为先插后删,slave同步的是binlog,因此会造成数据不一致。

InnoDB在分布式事务的情况下,一般会用到可串行化隔离级别

21:count(*),count(1)的区别

count(*)对行的数目进行计算,包括null

count(1)对特定的列的值具有的行数进行计算,不包括null    

count(1)跟count(主键)一样,只扫面主键,count(*)扫描整张表

22:sql优化

1):垂直分区

2):水平分区(水平分区之后的id,需要创建一个全局id,UUID,自增主键id,或者是使用redis)

3):索引下推:在遍历索引过程中,对索引中包含的字段先做判断,过滤掉不复合条件的记录,减少回表的次数(只适合在有二级索引的情况下)

4):覆盖索引:查询的条件在组合索引中,这样就不用进行回表操作

5):读写分离

6):限定数据的范围

23:数据库的主从同步

主从服务器的同步是依赖binlog日志的,master的变化记录在binlog中,然后从服务器读取binlog,并在本地保存一份自己的binlog,实现主从一致。

利用主从服务器来实现读写分离,从而分担了主服务器的压力。主服务器负责主动写的操作,而从服务器只负责读的操作。 一般是读多写少,读写分离一般是为了扩展读,提高并发吞吐和负载能力。

mysql默认采用异步复制的方式,这样从节点不用一直访问主服务器来更新自己的数据,数据的更新可以再远程连接上进行,从节点可以复制主数据库中的所有数据库或者特定的数据库,或者特定的表。

24:事务的四个特征

ACID:一致性,隔离性,持久性,原子性。

保证了原子性就能保证一致性吗?

原子性并不能完全保证一致性。一致性是最基本的属性,其他三个属性都是为了保证一致性而存在的。在多个事务并行进行的情况下,即使保证了每一个事务的原子性,仍然可能导致数据不一致的结果。

未来保证并发情况下的一致性,所以引入了隔离性。

25:sql慢查询

分为一直很慢和偶尔很慢。

偶尔很慢的情况:

1):加锁

2):写脏页

一直很慢:

索引使用不当

通过explain指令来查看

slow_query_log:慢查询开启状态

26:nosql和sql的区别

Sql:关系型数据库 nosql:非关系型数据库

区别:sql读写慢,nosql快速的读写

    Sql扩展困难,nosql简单的扩展

    Sql成本高,nosql成本低

    大多数nosql不支持事务

什么时候需要使用nosql

1):数据表的结构经常变化

2):数据库表字段是复杂数据类型

3):高并发数据库请求

4):海量数据的分布式存储

27:什么是覆盖索引?

指查询的列恰好是索引的一部分,那么查询只需要在索引文件上进行,不需要回表。

28:三范式

第一范式:列不可以再分成其他几列

第二范式:列依赖于主键

第三范式:非主键列必须直接依赖于主键,不能存在传递依赖。

29:为什么用聚集索引?

因为聚集索引中索引顺序和数据物理存储顺序一致,这样我们才可以找到数据。

30:myisam的优点

1):如果执行大量的select,myisam是更好的选择。因为myisam比较适合静态数据

2):数据是保存成文件的形式,在跨平台的数据转移中使用myisam存储会省去不少麻烦

31:锁机制于InnoDB锁算法

myisam:支持表级锁,表级锁又分为读锁和写锁。

innodb:支持的是行级锁和表级锁,默认是行级锁

record key:单个行记录上的锁

gap key:间隙锁,锁定一个范围,不包含记录本身。GAP锁的目的,是为了防止同一事物的两次当前读,出现幻读的情况。针对事务隔离级别为可重复读或以上级别的。

next-key lock:锁定一个范围,包含记录本身

32:binlog,redolog和undolog都是什么,有什么作用

binlog数据逻辑日志,在server层,用于记录所有更新且提交了数据或者已经潜在更新提交了数据,语句以statement的形式保存,保存了数据更改,用于复制,在主从复制中,从库利用主库上的binlog进行传播,实现主从同步。有三种模式:Statement(sql语句),Row(基于行的复制),Mixed(混合模式),用于数据库的基于时间点的还原。

redo log(重做日志):是innoDB中的日志,属于物理日志,确保事务的永久性。 redo log记录的是新数据的备份。在事务提交之前,只要将redo log持久化就行。

undo log:是为了实现事务的原子性,在mysql数据库InnoDB存储引擎中,还用undo log进行MVCC。原理是:在操作任何数据之前,首先将数据备份到一个地方。逻辑格式的日志,在执行undo的时候,仅仅是将数据从逻辑上恢复至事务之前的状态,而不是从物理页面上操作实现的。

33:什么是关系型数据库

关系型数据库是依据关系模型来创建的数据库

关系模型就是“一对一,一对多,多对多”等关系模型。关系模型就是指二维表格模型

关系型数据库的优点:

1):事务处理保持数据的一致性

2):由于以标准化为前提,数据更新的开销很小

3):可以进行join等复杂查询    

缺点:

1):扩展困难

2):读写慢, 3):成本高 4)有限的支撑容量。

34:order by的原理

1):利用索引的有序性获得有序数据

2):利用内存/磁盘文件排序获得结果

    双路排序:是首先根据相应的条件取出相应的排序字段和可以直接定位行数据的行指针信息,然后再sort buffer中进行排序

   单路排序:是一次性取出满足条件行的所有字段,然后再sort buffer中进行排序。

35:自增ID大于MAXINT后,数据库怎么办?

 int自增,最大为21亿条。

将int换成bigint。8字节。

36:分库分表之后,id主键如何处理

需要一个全局唯一得的来支持。

1):数据库自增id:两台数据库分别设置不同步长,生成不重复ID的策略来

2):UUID:太长了,占用空间大,作为主键性能太大了

3):利用redis生成id:性能较好,灵活方便,不依赖数据库。

4):美团的Leaf分布式ID生成系统。

37:mysql in查询是怎么实现的

优化器会将In子句中的条件看成是范围区间,每一个区间中只有一个值([b,b],[c,c])

在执行过程中就需要通过B+树去定位in中数目次的记录所在的位置。

所以如果写的IN语句中的参数越多,意味着需要通过B+树定位记录的次数就越多

38:数据发生更改,先更改数据库还是先更改缓存?如果先更新了缓存写数据失败了怎么办?即缓存不一致的情况?(如何保证redis与数据库的一致性)

更新的时候,先更新数据库,然后再删除缓存。如果先更新了数据库,删除缓存的时候失败了,那么缓存中还是老数据,数据库中是新数据,数据还是不一致。

重新理清场景:数据发生变更,先删除缓存,去修改数据库,此时一个请求过来去读缓存,发现缓存空了,去查询数据库,查到修改前的旧数据,放到缓存中,数据变更的程序完成了数据库的修改,结果数据库和缓存数据不一致了 

· 解决方案:

    串行化:把修改DB的操作放到一个JVM队列中,后面读的请求过来之后,“更新缓存”的操作也放到同一个队列中,对于一个作业线程,按照队列的顺序,依次执行相关的操作,这样就可以保证“更新缓存”一定是在DB修改之后,以保证数据的一致性。

39:mysql的乐观锁和悲观锁?

为什么需要锁?防止更新丢失,并不能单靠数据库事务控制器来解决,需要应用程序对要更新的数据加以必要的锁来解决

悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作(表锁)

乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。(MVCC)

40:Mysql连接池的作用

连接池的作用:将已经创建好的连接保存在池中,当有请求来时,直接使用已经创建好的连接对数据库进行访问。这样省略了创建连接和销毁连接的过程。

连接池中放的是N个Connection对象,本质上放在内存中,当内存中划出一块缓存对象,应用程序每次从池内获得Connection对象,而不是直接从数据里获取,这样不占用服务器的内存资源。

41:在rr级别下怎么解决幻读?

在快照读情况下,mysql通过MVCC来避免幻读 (快照读:监督的select操作,不加锁)

在当前读情况下,mysql通过next-key lock来避免幻读 (当前读:插入/更新/删除操作,需要加锁)

42:什么是MVCC

MVCC是多版本控制,mysql把每个操作都定义成一个事务,每开启一个事务,系统的事务版本号自动递增。每行记录都有两个隐藏的列:创建版本号和删除版本号。

43:sql注入

就是利用用户通过在表单中填写包含sql关键字的数据来使数据库执行非常规代码的过程。

使用预编译可以防止sql注入

sql注入的写法:用引号,在引号中间插入删库操作。

44:前缀索引

就是对文本的前几个字符建立索引,这样建立起来的索引更小,查询速度更快。但是不能在order by或者group by中使用前缀索引,也不能把他们作为覆盖索引。

45:SQL的表连接方式有哪些?

SQL中连接结果集分为:内连接,外连接,交叉连接

内连接:两张表都满足

外连接:左连接(以A表为基础,A表的全部数据,B表右的组合,没有的null),右连接,全连接

交叉连接:就是笛卡尔积

46:为什么用自增列作为主键

如果我们定义了主键,那么InnoDB会选择主键作为聚集索引

如果没有显示定义主键,那么InnoDB会选择第一个不包含有null值的唯一索引作为主键

如果也没有这样得唯一索引,则InnoDB会选择内置6字节得ROWID作为隐含得聚集索引。

如果表使用自增主键,那么每次插入新的数据,记录就会顺序添加到当前索引节点得后续位置,当一页写满之后,就会自动开辟一个新的页,那么可以防止页的分裂。

47:数据库崩溃时事务的恢复机制

主要利用redo log 和undo log

undo log:主要是为了实现事务的原子性,在Mysql的InnoDB存储引擎中,还用undo log实现了MVCC。

事务的原子性中,所有的操作,要么全部完成,要么不做任何操作,不能只做部分操作。如果在执行的过程中发生了错误,要回滚到事务开始之前的状态。所以在操作任何数据之前,首先要将数据备份到一个地方(这个存储数据备份的地方就是undo log),然后进行数据的修改。如果出现了错误或者用户执行了RollBack语句,系统可以利用undo log中的备份数据恢复到事务开始之前的状态。

**undolog必须先于数据持久化到磁盘**,如果在GH之间系统崩溃,undolog是完整的,可以用来回滚事务,如果在A-F之前系统崩溃,因为数据没有持久化到磁盘,所以磁盘上的数据还是保持在事务开始之前的状态。



redo log:redo log记录的是新数据的备份。在事务提交前,只要将redo log持久化就好了,不需要将数据持久化。当系统崩溃的时候,虽然数据没有持久化,但是redo log已经持久化。系统可以根据redo log的内容,将所有的数据恢复到最新的状态。



之所以能同时保证原子性和持久性,是因为以下特点:

**更新数据前记录redo log。为了保证持久性,那么必须将数据在事务提交之前写到磁盘中,只要事务成功提交,数据必然持久化**。undo log必须先于数据持久化到磁盘。

48:mysql问题排查都有哪些手段?

使用show processlist命令查看当前所有连接情况

使用explain命令查询sql语句执行计划

开启慢查询日志,查看慢查询的SQL slow_query_log

49:为什么索引降低增删改的速度

因为B+树是一颗平衡的树,如果我们对这颗树进行增删改的话,那么一定会破坏它的原有结构;要维持平衡树,就必须做额外的工作。正因为这些额外的工作开销,导致索引会降低增删改的速度。

50:一条mysql语句在mysql中如何执行?

1):查询语句:

     通过Tcp连接到MYSQL连接器,检查连接权限及资源分配。

     发送SQL,如果是select语句,再看开没开缓存(需要开启缓存),开了缓存的话使用将SQLhash去匹配,如果匹配成功直接返回结果,并不使用分析器。

    未命中缓存,分析器(词法,语法)。然后到预处理器,检查数据表和数据列是否存在,解析别名看是否存在歧义等。然后交给优化器优化(索引的选择之类的),生成执行计划。

    通过执行器,调用存储引擎api

2):更新语句:    

权限校验,看是否可以进行连接,连接好了走分析器,优化器,执行器,通过执行器调用存储引擎的api,并把这个操作记录到redo log中,此时redo log处于prepare状态,随时可以提交事务。随后执行生成操作的binlog,并把binlog写入到磁盘。最后执行器调用InnoDB提交事务的接口,把刚刚的redo log改为commit状态。这就是两阶段提交的概念。

51:MySQl主从复制的主要用途

主要用于读写分离

在开发工程中,有时候会遇到某个sql语句需要锁表,导致暂时不能使用读的服务,这样就会影响现有业务,使用主从复制,让主库负责写,从库负责读,这样,即使主库出现了锁表的情况,通过读从库也可以保证业务的正常进行。而且一般是读多写少

数据实时备份,当系统中某个节点发生故障时,可以方便的故障切换。

高可用性。

52:mysql中的各种锁

在InnoDB中,**我们的锁都是作用在索引上的**,只有当我们的sql命中索引时,才会触发行锁,没有命中的时候,我们的锁都是使用的表锁。

表锁:锁住整张表

行锁:锁住表的某一行或者多行记录。

record Lock(记录锁):事务加锁后锁住的只是表的某一条记录。精准条件命中,并且命中的条件字段是唯一索引。 加了记录锁之后,可以避免数据在查询的时候被修改的重复读问题,也避免了在修改的事务未提交前被其他事务读取的脏读问题。

Gap Lock(间隙锁):事务加锁后锁住的是表记录的某一区间。当表的相邻ID之间出现空隙则会形成一个区间,遵循左闭右开。范围查询并且查询没有命中记录,查询条件必须命中索引,**间隙锁只会出现在重复读的事务中**。

next-key Lock:是InnoDB的行锁默认算法,是记录锁和间隙锁的组合。next-key Lock会把查询出来的记录锁住,同时也会把该范围查询内的所有间隙空间也会锁住。避免了出现脏读,重复读,幻读问题。

共享锁:一个事务为数据加上读锁之后,其他事务只能读该数据加读锁。

排他锁:当一个事务为数据加上X锁之后,其他请求将不能再为数据加任何锁。

53: limit慢的原因

索引的底层是B+树,直接通过叶子节点组成的链表,以O(n)的时间复杂度找到第100大的树,但是还有其他的原因

因为数据库中有:

    聚集索引:包含主键索引和对应的实际数据,索引的叶子节点就是数据节点

    非聚集性索引:其叶子节点还是索引节点,包含了主键id

即使前10000扔掉,mysql仍然会通过二级索引上的主键id,去聚集索引上查一遍数据,这可是1000次随机io,自然很慢。,limit offset智能作用与引擎层返回的结果集,但是引擎曾也不知道这10000个是要扔掉的。

54:怎么看mysql索引失效呢?

通过explain+sql来看mysql索引是否失效,主要是ref字段的指向。

55:mysql的主键索引和唯一索引有什么区别

唯一索引不允许两行具有相同的索引值,**主键索引是唯一索引的特殊类型**,数据库表通常有一列或列组合,其值用来唯一表示表中的每一行。该列称为表的主键。

主键不一定只包含一个字段,所以如果你在主键的其中一个字段建唯一索引还是必要的

主键可以做外键,但是唯一索引不可以

主键不可以为空,唯一索引可以

主键也可是多个字段的组合。

56:Mysql更新语句怎么加锁?

    在快照读的情况下:读取的是记录中的可见版本,不用加锁

    在当前读的情况下:读取的是记录中最新版本,并且当前读返回的记录都会加上锁,这样保证了其他事务不会再并发修改这条记录。(next-key lock)

57:in和exists的区别

① Mysql中的in把外表和内表做hash连接,而exists语句是对外表做loop循环,每次loop循环再对内表进行查询。

② 子表数据量比外表数据量少,使用in。

③ 子表数据量比外表数据量大,使用exists。

④ 子表与外表数据量大小差不多,用in与exists的效率相差不大。

⑤ Not in内外表都要进行全表扫描,not exists的子查询依然能用到表上索引。

58:mysql分库分表

(1)按时间分表,针对有较强时效性的数据,如微博发送记录,微信消息记录等。将6个月前或一年前的数据切出去放在另外一张表。

(2)按区间范围分表。一般在有严格的自增id需求上,比如按照id水平分表。

(3)Hash取模,对用户id进行hash取模,分配到不同数据库上。

59:Mysql中的死锁

(1)当事务试图以不同顺序锁定资源时,就可能产生死锁。InnoDB存储引擎能检测到死锁的循环依赖并立即返回一个错误。

(2)InnoDB目前处理死锁的方法是,将持有最少排他锁的事务进行回滚。所以事务型应用程序在设计时必须考虑如何处理死锁,多数情况下只需要重新执行因死锁回滚的事务即可。

(3)若涉及到外部锁或表锁的情况下,innodb不能完全自动检测到死锁,需要通过设置锁等待超时参数来解决。

60:试图和表的区别

1:视图是已经编译好的sql语句,而表不是

2:视图没有实际的物理记录,而表有

3:表是内容,视图是窗口

4:表只用物理空间而视图不占用物理空间,视图只是逻辑概念的存在,表可以及时对它进行修改,但视图只能由创建的语句来修改

5:表是内模式,视图是外模式

6:视图的创建和删除只影响视图本身,不影响对应的基本表。

61:二维数组,行遍历和列遍历,哪一个更快?从CPU缓存的角度来解释一下

按行遍历的效率大概是按列遍历的0.5倍

1):CPU高速缓存:用于减少处理器访问内存所需平均时间的部件。

2):缓存从内存中抓取一般都是整个数据块,所以他的物理内存是连续的,几乎都是同行不同列。如果是以列的方式进行遍历的话,将会使整个缓存块无法被利用,而不得不从内存中读取数据。

62:抽象类和普通类的区别

1):抽象类不能被实例化

2):抽象类可以有构造函数,抽象方法不能被声明为静态

3):抽象方法只需要声明而不需要实现。

4):抽象类的子类必须实现抽象方法,否则这个子类也是抽象类

63:redis的优缺点

优点:

1):支持多种数据类型

2):持久化存储

3):性能好,内存操作

缺点:

1):由于redis是内存数据库,所以,单台机器,存储的数据量,跟机器本身的的内存大小有关

2):redis是单线程的,单台服务器无法充分利用多核服务器的CPU。

64:数据库查询如何去重?

distinct

62:数字银行和普通银行卡相比的优劣势

  1. 数字银行卡可实现在线申领、轻松管理等,用户足不出户就可快速办理、使用银行卡

  2. 节约人力,物力成本,网上办理、没有实体卡、方便快捷

  3. 多平台使用,全球通用

    劣势:

    1:功能上的完备性:消费额度,使用场景等

    2:安全性:普通银行卡经过诺干年的考验,有一套相对而言比较完善的体系,数字银行刚刚提出,必然存在安全上的隐患。

你可能感兴趣的:(高频面试题——数据库)