C++面试题汇总 数据库

C++面试题汇总 数据库

  • 数据库基础
    • 数据库索引
    • 数据库事务
    • 数据库事务隔离
    • `inner join`, `left join`, `right join`,`full join`
    • 数据库事务的一致性
    • 索引是什么,多加索引一定会好吗
    • 数据库的三大范式
    • 数据库的`ACID`特性
  • `SQL`
    • `MySQL`主要包含四种隔离状态:
    • `MySQL`的`MVCC`机制
    • `SQL`优化方法有哪些
    • `MySQL`引擎和区别
    • `Mysql`引擎以及其区别
  • `Redis`
    • `mongodb`和`Redis`的区别
    • `Redis`的定时机制怎么实现的
    • `Redis`是单线程的,但是为什么这么高效呢?
    • `Redis`的数据类型有哪些,底层怎么实现?
    • `Redis`的`rehash`怎么做的,为什么要渐进`rehash`,渐进`rehash`又是怎么实现的?
    • `Redis`和`memcached`的区别

数据库基础

数据库索引

  1. 数据库索引对数据库表一列或多列的值进行排序的一种结构, 是为了增加查询速度而对表字段附加的一种标识
  2. DB在执行一条Sql语句的时候,默认的方式是根据搜索条件进行全表扫描,遇到匹配条件的就加入搜索结果集合。
  3. 如果我们对某一字段增加索引,查询时就会先去索引列表一次定位到特定值的行数,大大减少遍历匹配的行数,所以能明显增加查询的速度。

数据库事务

  • 数据库事务(Database Transaction),是指对单个逻辑工作单元执行的一系列操作要么完全地执行,要么完全地不执行
  • 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源
  • (操作) 通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠
  • (事务) 一个逻辑工作单元要成为事务,必须满足所谓的 ACID(原子性(Atomicity)一致性(Consistency)隔离性(Isolation)持久性(Durability))属性。事务是数据库运行中的逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理。

数据库事务隔离

  • 隔离性(Isolation)
    • 隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

      • 即要达到这么一种效果:对于任意两个并发的事务T1T2,在事务T1看来,
        • T2要么在T1开始之前就已经结束,
        • 要么在T1结束之后才开始,
        • 这样每个事务都感觉不到有其他事务在并发地执行。
    • 多个并发事务相互隔离,即一个事务不应该影响其它事务运行效果。

      • 这指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。
      • 由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。
    • 不同的隔离级别:

      • Read Uncommitted(读取未提交内容):最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果。所有的并发事务问题都会发生。
      • Read Committed(读取提交内容):只有在事务提交后,其更新结果才会被其他事务看见。可以解决脏读问题
      • Repeated Read(可重复读):在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。可以解决脏读、不可重复读
      • Serialization(可串行化):事务串行化执行,隔离级别最高,牺牲了系统的并发性可以解决并发事务的所有问题

inner join, left join, right join,full join

  • inner join(内连接): 只返回两个表中联结字段相等的行
  • left join(左联接): 返回包括左表中的所有记录右表中联结字段相等的记录
  • right join(右联接): 返回包括右表中的所有记录左表中联结字段相等的记录
  • full join(外连接): 返回两个表中的行

数据库事务的一致性

  • 事务(Transaction)是由 一系列对系统中数据进行访问与更新的操作 所组成的一个程序执行逻辑单元

  • 事务是DBMS中最基础的单位,它不可分割。


  • 事务具有4个基本特征(ACID),分别是:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Duration),简称ACID

  • 原子性(Atomicity)

    • 原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响
  • 一致性(Consistency)

    • 一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态
    • 拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管AB之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
  • 隔离性(Isolation)

    • 隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离
      • 即要达到这么一种效果:对于任意两个并发的事务T1T2,在事务T1看来,
        • T2要么在T1开始之前就已经结束,
        • 要么在T1结束之后才开始,
        • 这样每个事务都感觉不到有其他事务在并发地执行。
    • 多个并发事务相互隔离这指的是
      • 在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。
      • 由并发事务所做的修改必须与任何其他并发事务所做的修改隔离
    • 不同的隔离级别
      • Read Uncommitted(读取未提交内容):最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果。所有的并发事务问题都会发生。
      • Read Committed(读取提交内容):只有在事务提交后,其更新结果才会被其他事务看见。可以解决脏读问题
      • Repeated Read(可重复读):在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。可以解决脏读、不可重复读
      • Serialization(可串行化):事务串行化执行,隔离级别最高,牺牲了系统的并发性可以解决并发事务的所有问题
  • 持久性(Durability)

    • 持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
    • 例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。

索引是什么,多加索引一定会好吗

  • 索引
    • 数据库索引是对数据库表一列或多列的值进行排序的一种结构, 是为了增加查询速度而对表字段附加的一种标识
    • DB在执行一条Sql语句的时候,默认的方式是根据搜索条件进行全表扫描,遇到匹配条件的就加入搜索结果集合。
    • 如果我们对某一字段增加索引,查询时就会先去索引列表一次定位到特定值的行数,大大减少遍历匹配的行数,所以能明显增加查询的速度。
  • 优点:唯一性, 加快数据检索速度, 加速表的连接, 加速分组和排序, 使用优化隐藏器
    • 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性
    • 可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
    • 可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
    • 在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
    • 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。

    • sql 的优化隐藏器是什么

  • 缺点:创建和维护, 降低维护速度, 占物理空间
    • 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
    • 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度
    • 索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。

  • 添加索引原则: N少用, N少值, N特定类型, 性能需求
    • 在查询中很少使用或者参考的列不应该创建索引。
      • 这是因为,既然这些列很少使用到,因此有索引或者无索引,并不能提高查询速度。
      • 相反,由于增加了索引,反而降低了系统的维护速度和增大了空间需求。
    • 只有很少数据值的列也不应该增加索引。
      • 这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。
      • 增加索引,并不能明显加快检索速度。
    • 定义为 textimagebit数据类型 的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少。
    • 修改性能远远大于检索性能时,不应该创建索引。
      • 这是因为,修改性能和检索性能是互相矛盾的。
      • 当增加索引时,会提高检索性能,但是会降低修改性能。
      • 当减少索引时,会提高修改性能,降低检索性能。
      • 因此,当修改性能远远大于检索性能时,不应该创建索引。

数据库的三大范式

数据库的设计范式是数据库设计所需要满足的规范,满足这些规范的数据库是简洁的、结构明晰的,同时,不会发生插入(insert)、删除(delete)和更新(update)操作异常。

  • 第一范式:当关系模式R的所有属性都不可再分为更基本的数据单位时,称R是满足第一范式,即属性不可分
  • 第二范式:如果关系模式R满足第一范式,并且R的所有非主属性都完全依赖于R每一个候选关键属性,称R满足第二范式
  • 第三范式:如果关系模式R满足第一范式, 且R中的任意属性集, 都非传递依赖R任意一个候选关键属性,称R满足第三范式,即非主属性不传递依赖于键码

  • 参考: 数据库三大范式 - 凉亭的博客 - CSDN博客
  • 第一范式(1NF):列不可再分
    • 每一列属性都是不可再分的属性值,确保每一列的原子性
    • 两列的属性相近或相似或一样,尽量合并属性一样的列,确保不产生冗余数据
  • 第二范式(2NF): 属性完全依赖于主键
    • 第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)
    • 第二范式(2NF)要求数据库表中的每个实例或行必须可以被惟一地区分。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。这个惟一属性列被称为主键
  • 第三范式(3NF): 属性不依赖于其它非主属性, 属性直接依赖于主键
    • 数据不能存在传递关系,即每个属性都跟主键有直接关系而不是间接关系。

数据库的ACID特性

  • 事务(Transaction)是由 一系列对系统中数据进行访问与更新的操作 所组成的一个程序执行逻辑单元

  • 事务是DBMS中最基础的单位,它不可分割。


  • 事务具有4个基本特征(ACID),分别是:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Duration),简称ACID

  • 原子性(Atomicity)

    • 原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响
  • 一致性(Consistency)

    • 一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态
    • 拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管AB之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
  • 隔离性(Isolation)

    • 隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离
      • 即要达到这么一种效果:对于任意两个并发的事务T1T2,在事务T1看来,
        • T2要么在T1开始之前就已经结束,
        • 要么在T1结束之后才开始,
        • 这样每个事务都感觉不到有其他事务在并发地执行。
    • 多个并发事务相互隔离这指的是
      • 在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。
      • 由并发事务所做的修改必须与任何其他并发事务所做的修改隔离
    • 不同的隔离级别
      • Read Uncommitted(读取未提交内容):最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果。所有的并发事务问题都会发生。
      • Read Committed(读取提交内容):只有在事务提交后,其更新结果才会被其他事务看见。可以解决脏读问题
      • Repeated Read(可重复读):在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。可以解决脏读、不可重复读
      • Serialization(可串行化):事务串行化执行,隔离级别最高,牺牲了系统的并发性可以解决并发事务的所有问题
  • 持久性(Durability)

    • 持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
    • 例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。

SQL

MySQL主要包含四种隔离状态:

事务隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted)
不可重复读(read-committed)
可重复读(repeatable-read)
串行化(serializable)

  • 脏读:事务A读到了事务B未提交的数据。
  • 不可重复读:事务A第一次查询得到一行记录row1,事务B提交修改后,事务A第二次查询得到row1,但列内容发生了变化。
  • 幻读:事务A第一次查询得到一行记录row1,事务B提交修改后,事务A第二次查询得到两行记录row1row2

MySQLMVCC机制

  • MVCC是一种多版本并发控制机制,是MySQLInnoDB存储引擎实现隔离级别的一种具体方式,用于实现提交读可重复读这两种隔离级别。
  • MVCC是通过保存数据在某个时间点的快照来实现该机制,其在每行记录后面保存两个隐藏的列,分别保存这个行的创建版本号删除版本号,然后InnoDBMVCC使用到的快照存储在Undo日志中,该日志通过回滚指针把一个数据行所有快照连接起来。

SQL优化方法有哪些

  • 通过建立索引对查询进行优化, 对查询进行优化,应尽量避免全表扫描

  • 参考: SQL优化有哪些方法? - Hello_Rainy的博客 - CSDN博客
  • SQL优化方法
    1. 建立索引优先考虑wheregroup by使用到的字段(较频繁地作为查询条件且唯一性不太差),不会在where中用到的字段不建立索引,因为建立索引也需要系统的开销。
    2. 减少使用 *,用列名代替
      • select * from user, 改写 select userID, userName, userSalary from user;
      • 因为在使用 * 的时候,数据库还得查询数据字典,进而解析得到列名,而直接写出列名效率会更高些。
    3. 避免在开头使用模糊查询(%),该查询数据库引擎会放弃索引进行全表扫描。
    4. 避免进行NULL值判断,可以给字段添加默认值0,对0值进行判断;也不要给数据库留NULL,使用NOT NULL填充。(否则会进行全表扫描,影响效率)
    5. 避免在where条件中等号的左边进行表达式或函数操作,可以将表达式或函数移到等号右边。(否则会全表扫描)
    6. 当使用where子句连接的时候,要把能过滤掉最大数量记录的条件写在最右边。(因为where是从右往左解析的)
    7. 需要删除所有记录的时候,用truncate而不用detele
      • 因为delete删除表的时候,会扫描整个表再一条一条删除;
      • truncate会一次性删除整个表的所有内容,不进行扫描,效率高。
    8. wherehaving都用的时候,先用where,再用havingwhere先过滤(数据量变少),再分组,效率高。
    9. 避免使用innot in,会导致全表扫描
      • 优化方式:如果是连续数值,用between代替;如果是子查询,用exists代替。
    10. 如果表名或列名过长,就使用别名,因为长的表名和列名也会消耗扫描时间。

    • 整理了一下:
    • 建立索引优先将经常作为wheregroup by的索引的子段
    • 几种加速的策略:
      • 如果表名或则列名太长,就使用别名
      • 减少使用全部选择符*,
      • 使用使用where连接选择的时候, 将能筛选能力最强的子段放在最右边(从右往左解析)
      • 删除所有记录时,使用truncate提到delete
    • 避免几种会导致全表扫描的情况, 如下:
      • 在开头使用模糊查询
      • 使用innot in会导致全表查询
      • where条件中等号的左端使用表达式或函数

MySQL引擎和区别

  • MySQL引擎
    • MySQL中的数据用各种不同的技术存储在文件(或者内存)中。这些技术中的每一种技术都使用不同的存储机制、索引技巧、锁定水平并且最终提供广泛的不同的功能和能力。通过选择不同的技术,你能够获得额外的速度或者功能,从而改善你的应用的整体功能。
    • 数据库引擎是用于存储、处理和保护数据的核心服务。利用数据库引擎可控制访问权限并快速处理事务,从而满足企业内大多数需要处理大量数据的应用程序的要求。使用数据库引擎创建用于联机事务处理或联机分析处理数据的关系数据库。这包括创建用于存储数据的表和用于查看、管理和保护数据安全的数据库对象(如索引、视图和存储过程)。
    • MySQL存储引擎主要有:MyIsamInnoDBMemoryBlackholeCSVPerformance_SchemaArchiveFederatedMrg_Myisam
    • 但是最常用的是InnoDBMylsam
  • InnoDB
    • InnoDB是一个事务型的存储引擎,有行级锁定外键约束
    • Innodb引擎提供了对数据库ACID事务的支持,并且实现了SQL标准的四种隔离级别,关于数据库事务与其隔离级别的内容请见数据库事务与其隔离级别这类型的文章。
    • 该引擎还提供了行级锁和外键约束,它的设计目标是处理大容量数据库系统,它本身其实就是基于MySQL后台的完整数据库系统,MySQL运行时Innodb会在内存中建立缓冲池,用于缓冲数据和索引。
    • 但是该引擎不支持FULLTEXT类型的索引,而且它没有保存表的行数,当SELECT COUNT(*) FROM TABLE时需要扫描全表。
    • 当需要使用数据库事务时,该引擎当然是首选
    • 由于锁的粒度更小,写操作不会锁定全表,所以在并发较高时,使用Innodb引擎会提升效率。
    • 但是使用行级锁也不是绝对的,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表。
  • 适用场景:
    • 经常更新的表,适合处理多重并发的更新请求
    • 支持事务。
    • 可以从灾难中恢复(通过bin-log日志等)。
    • 外键约束。只有他支持外键
    • 支持自动增加列属性auto_increment
  • 索引结构:
    • InnoDB也是B+Treee索引结构。InnoDB的索引文件本身就是数据文件,即B+Tree的数据域存储的就是实际的数据,这种索引就是聚集索引。这个索引的key就是数据表的主键,因此InnoDB表数据文件本身就是主索引。
    • InnoDB的辅助索引数据域存储的也是相应记录主键的值而不是地址,所以当以辅助索引查找时,会先根据辅助索引找到主键,再根据主键索引找到实际的数据。所以 Innodb不建议使用过长的主键 ,否则会使辅助索引变得过大。建议使用自增的字段作为主键,这样B+Tree的每一个结点都会被顺序的填满,而不会频繁的分裂调整,会有效的提升插入数据的效率。
    • 参考: MySql索引类型 - Unique-You的博客 - CSDN博客

  • 参考:
    • BTree和B+Tree详解 - 菜鸟笔记 - CSDN博客
    • BTree和B+Tree详解 - end’s coding life - CSDN博客
    • BTree: 对于mBTree
      • 每个节点最多有m个孩子节点
      • 除了根结点和叶子结点,其他节点至少有ceil(m/2)个节点
      • 非叶子结点的根节点至少有2个孩子节点
      • 所有叶子结点都位于同一层,且不包含其他关键节点信息
      • 所有非终端节点至少包括的关键字个数应该大于等于ceil(m/2),小于等于m
      • 这些关键字升序排列
      • 子树的所有关键字小于对应父节点关键字, 但是大于前一个兄弟节点的关键字
    • B+Tree相对于B-Tree有几点不同:
      • 非叶子节点只存储键值信息。
      • 数据记录都存放在叶子节点中。
      • 所有叶子节点之间都有一个链指针。

  • Mylsam
    • MyIASMMySQL默认的引擎,但是它没有提供对数据库事务的支持,也不支持行级锁和外键,因此当INSERTUPDATE数据时即写操作需要锁定整个表,效率便会低一些。MyIsam存储引擎独立于操作系统,也就是可以在windows上使用,也可以比较简单的将数据转移到linux操作系统上去。
  • 适用场景:
    • 不支持事务的设计,但是并不代表着有事务操作的项目不能用MyIsam存储引擎,可以在service层进行根据自己的业务需求进行相应的控制。
    • 不支持外键的表设计
    • 查询速度很快,如果数据库insertupdate的操作比较多的话比较适用。
    • 整天对表进行加锁的场景
    • MyISAM极度强调快速读取操作。
    • MyIASM中存储了表的行数,于是SELECT COUNT(*) FROM TABLE时只需要直接读取已经保存好的值而不需要进行全表扫描。
    • 如果表的读操作远远多于写操作且不需要数据库事务的支持,那么MyIASM也是很好的选择。
  • 缺点:就是不能在表损坏后主动恢复数据。
  • 索引结构:
    • MyISAM索引结构:MyISAM索引用的B+ tree来储存数据,MyISAM索引的指针指向的是键值的地址,地址存储的是数据。B+Tree的数据域存储的内容为实际数据的地址,也就是说它的索引和实际的数据是分开的,只不过是用索引指向了实际的数据,这种索引就是所谓的非聚集索引
    • 参考: MySql索引类型 - Unique-You的博客 - CSDN博客
  • InnoDBMylsam的区别:
    1. 事务:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持,提供事务支持已经外部键等高级数据库功能。
    2. 锁的支持:MyISAM只支持表锁。InnoDB支持表锁、行锁 行锁大幅度提高了多用户并发操作的新能。但是InnoDB的行锁,只是在WHERE的主键是有效的,非主键的WHERE都会锁全表的。
    3. 行数保存:InnoDB中不保存表的具体行数,也就是说,执行select count() fromtable时,InnoDB要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count()语句包含where条件时,两种表的操作是一样的。
    4. 性能:MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快。
    5. 索引存储:
      • 对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引。MyISAM支持全文索引(FULLTEXT)、压缩索引,InnoDB不支持。
      • MyISAM的索引和数据是分开的,并且索引是有压缩的,内存使用率就对应提高了不少。能加载更多索引,而Innodb是索引和数据是紧密捆绑的,没有使用压缩从而会造成InnodbMyISAM体积庞大不小。
      • InnoDB存储引擎被完全与MySQL服务器整合,InnoDB存储引擎为在主内存中缓存数据和索引而维持它自己的缓冲池。InnoDB存储它的表&索引在一个表空间中,表空间可以包含数个文件(或原始磁盘分区)。这与MyISAM表不同,比如在MyISAM表中每个表被存在分离的文件中。InnoDB表可以是任何尺寸,即使在文件尺寸被限制为2GB的操作系统上。
    6. 服务器数据备份:
      • InnoDB必须导出SQL来备份,LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。
      • MyISAM应对错误编码导致的数据恢复速度快。MyISAM的数据是以文件的形式存储,所以在跨平台的数据转移中会很方便。在备份和恢复时可单独针对某个表进行操作。
      • InnoDB是拷贝数据文件、备份binlog,或者用mysqldump,在数据量达到几十G的时候就相对痛苦了。

Mysql引擎以及其区别

  • Mysql数据库中,常用的引擎为InnodbMyIASM
  • 参考上一个问题: MySQL引擎和区别

Redis

mongodbRedis的区别

  • 内存管理机制上:
    • Redis数据全部存在内存,定期写入磁盘,当内存不够时,可以选择指定的LRU算法删除数据。
    • MongoDB数据存在内存,由linux系统mmap实现,当内存不够时,只将热点数据放入内存,其他数据存在磁盘。
  • 支持的数据结构上:
    • Redis支持的数据结构丰富,包括hashsetlist等。
    • MongoDB数据结构比较单一,但是支持丰富的数据表达,索引,最类似关系型数据库,支持的查询语言非常丰富

Redis的定时机制怎么实现的

  • Redis服务器是一个事件驱动程序,服务器需要处理以下两类事件:
    • 文件事件:Redis服务器通过套接字与客户端(或者其他Redis服务器)进行连接,而文件事件就是服务器对套接字操作的抽象。服务器与客户端(或者其他服务器)的通信会产生相应的文件事件,而服务器则通过监听并处理这些事件来完成一系列网络通信操作;
    • 时间事件: Redis服务器中的一些操作(比如serverCron函数)需要在给定的时间点执行,而时间事件就是服务器对这类定时操作的抽象。
  • Redis的定时机制就是借助时间事件实现的。
  • 一个时间事件主要由以下三个属性组成:
    • id:时间事件标识号;
    • when:记录时间事件的到达时间;
    • timeProc:时间事件处理器,当时间事件到达时,服务器就会调用相应的处理器来处理时间事件。
    • 一个时间事件根据时间事件处理器的返回值来判断是定时事件还是周期性事件
  • 文件事件处理器的四个组成部分:
    • 套接字: 文件事件是对套接字操作的抽象, 当每个套接字准备好执行应答写入读取关闭等操作时, 就会产生一个文件事件。因为一个服务器通常会连接多个套接字,所以多个文件事件有可能会并发地出现。
    • I/O多路复用程序: 负责监听多个套接字,并向文件事件分派器传送那些产生了事件的套接字。尽管多个文件事件可能会并发地出现,但I/O多路复用程序总是会将所有产生事件的套接字都放到一个队列里面,然后通过这个队列,以有序(sequentially)、同步(synchronously)、每次一个套接字的方式向文件事件分派器传送套接字。
    • 文件事件分派器(dispatcher): 接收I/O多路复用程序传来的套接字,并根据套接字产生的事件的类型,调用相应的事件处理器;
    • 事件处理器: 事件处理器是一个个函数,它们定义了某个事件发生时,服务器应该执行的动作。
      C++面试题汇总 数据库_第1张图片
      IO多路复用器

  • 参考: 文件事件 - TuxedoLinux的博客 - CSDN博客

Redis是单线程的,但是为什么这么高效呢?

  • Redis将套接字操作抽象为了文件事件, 当每个套接字准备好执行应答写入读取关闭等操作时, 就会产生一个文件事件。因为一个服务器通常会连接多个套接字,所以多个文件事件有可能会并发地出现。
  • 文件事件处理器的四个组成部分:
    • 套接字: 文件事件是对套接字操作的抽象, 当每个套接字准备好执行应答写入读取关闭等操作时, 就会产生一个文件事件。因为一个服务器通常会连接多个套接字,所以多个文件事件有可能会并发地出现。
    • I/O多路复用程序: 负责监听多个套接字,并向文件事件分派器传送那些产生了事件的套接字。尽管多个文件事件可能会并发地出现,但I/O多路复用程序总是会将所有产生事件的套接字都放到一个队列里面,然后通过这个队列,以有序(sequentially)、同步(synchronously)、每次一个套接字的方式向文件事件分派器传送套接字。
    • 文件事件分派器(dispatcher): 接收I/O多路复用程序传来的套接字,并根据套接字产生的事件的类型,调用相应的事件处理器;
    • 事件处理器: 事件处理器是一个个函数,它们定义了某个事件发生时,服务器应该执行的动作。
    • 参考上一个问题: Redis的定时机制怎么实现的

Redis的数据类型有哪些,底层怎么实现?

  1. 字符串:整数值、embstr编码的简单动态字符串、简单动态字符串(SDS)
  2. 列表:压缩列表、双端链表
  3. 哈希:压缩列表、字典
  4. 集合:整数集合、字典
  5. 有序集合:压缩列表、跳跃表和字典

Redisrehash怎么做的,为什么要渐进rehash,渐进rehash又是怎么实现的?

  • 因为redis是单线程,当K很多时,如果一次性将键值对全部rehash,庞大的计算量会影响服务器性能,甚至可能会导致服务器在一段时间内停止服务。不可能一步完成整个rehash操作,所以redis是分多次、渐进式的rehash
  • 渐进性哈希分为两种:
    1. 操作redis时,额外做一步rehash, 对redis做读取、插入、删除等操作时,会把位于table[dict->rehashidx]位置的链表移动到新的dictht中,然后把rehashidx做加一操作,移动到后面一个槽位。
    2. 后台定时任务调用rehash, 后台定时任务rehash调用链,同时可以通过server.hz控制rehash调用频率

Redismemcached的区别

  1. 数据类型 :redis数据类型丰富,支持set liset等类型;memcache支持简单数据类型,需要客户端自己处理复杂对象
  2. 持久性:redis支持数据落地持久化存储;memcache不支持数据持久存储。)
  3. 分布式存储:redis支持master-slave复制模式;memcache可以使用一致性hash做分布式。
  4. value大小不同:memcache是一个内存缓存,key的长度小于250字符,单个item存储要小于1M,不适合虚拟机使用
  5. 数据一致性不同:redis使用的是单线程模型,保证了数据按顺序提交;memcache需要使用cas保证数据一致性。CAS(Check and Set)是一个确保并发一致性的机制,属于“乐观锁”范畴;原理很简单:拿版本号,操作,对比版本号,如果一致就操作,不一致就放弃任何操作
  6. cpu利用:redis单线程模型只能使用一个cpu,可以开启多个redis进程

你可能感兴趣的:(C++面试题目汇总)