数据库面试题

数据库面试知识点汇总

一、基本概念

1. 主键、外键、超键、候选键

  • 超键:在关系中能唯一标识元组的属性集称为关系模式的超键。一个属性可以为作为一个超键,多个属性组合在一起也可以作为一个超键。超键包含候选键和主键。
  • 候选键:是最小超键,即没有冗余元素的超键。
  • 主键:数据库表中对储存数据对象予以唯一和完整标识的数据列或属性的组合。一个数据列只能有一个主键,且主键的取值不能缺失,即不能为空值(Null)。
  • 外键:在一个表中存在的另一个表的主键称此表的外键。

2. 存储过程的优缺点?

  • 优点:
    1. 存储过程是预编译过的,执行效率高。
    2. 存储过程的代码直接存放于数据库中,通过存储过程名直接调用,减少网络通讯。
    3. 安全性高,执行存储过程需要有一定权限的用户。
    4. 存储过程可以重复使用,可减少数据库开发人员的工作量。
  • 缺点:移植性差

3. 一条SQL查询语句是如何执行的?(**)

  • Server 层:连接器、查询缓存、分析器、优化器、执行器
  • 存储引擎层: InnoDB、MyISAM、Memory
  • 执行步骤:
    1. 连接器:连接上数据库,连接器负责管理连接,权限校验
    2. 查询缓存,命中直接返回结果(更新失效,命中率第,MySQL 8.0删除此功能)
    3. 分析器:词法分析,语法分析
    4. 优化器:执行计划生成,索引选择,决定各个表的连接顺序
    5. 执行器:操作引擎,返回结果
    6. 存储引擎:存储数据,提供读写接口

4. 重要的日志模块(**)

  • redo log
    1. InnoDB 引擎就会先把记录写到 redo log(粉板)里面,并更新内存,这个时候更新就算完成了。
    2. 同时,InnoDB 引擎会在适当的时候,将这个操作记录更新到磁盘里面,而这个更新往往是在系统比较空闲的时候做,这就像打烊以后掌柜做的事。
    3. InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失(crash-safe)。
  • binlog
    1. Server 层自己的日志。
    2. redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。
    3. redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如“给 ID=2 这一行的 c 字段加 1 ”。
    4. redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。
    5. 两阶段提交:redo log prepare -> binlog。

5. 非关系型数据库和关系型数据库区别,优势比较?

  • 非关系型数据库的优势:
    1. 性能:NOSQL是基于键值对的,可以想象成表中的主键和值的对应关系,而且不需要经过SQL层的解析,所以性能非常高。
    2. 可扩展性:同样也是因为基于键值对,数据之间没有耦合性,所以非常容易水平扩展。
  • 关系型数据库的优势:
    1. 复杂查询:可以用SQL语句方便的在一个表以及多个表之间做非常复杂的数据查询。
    2. 事务支持:使得对于安全性能很高的数据访问要求得以实现。
  • 其他:
    1. 对于这两类数据库,对方的优势就是自己的弱势,反之亦然。
    2. NOSQL数据库慢慢开始具备SQL数据库的一些复杂查询功能,比如MongoDB。
    3. 对于事务的支持也可以用一些系统级的原子操作来实现例如乐观锁之类的方法来曲线救国,比如Redis set nx。

6. count(*)、count(1)、count(column)的区别

  • count(*)对行的数目进行计算,包含NULL。
  • count(column)对特定的列的值具有的行数进行计算,不包含NULL值。
  • count()还有一种使用方式,count(1)这个用法和count(*)的结果是一样的。
  • 性能问题:
    1. 任何情况下SELECT COUNT(*) FROM tablename是最优选择;
    2. 尽量减少SELECT COUNT(*) FROM tablename WHERE COL = ‘value’ 这种查询;
    3. 杜绝SELECT COUNT(COL) FROM tablename WHERE COL2 = ‘value’ 的出现。
  • 如果表没有主键,那么count(1)比count(*)快。
  • 如果有主键,那么count(主键,联合主键)比count(*)快。
  • 如果表只有一个字段,count(*)最快。
  • count(1)跟count(主键)一样,只扫描主键。count(*)跟count(非主键)一样,扫描整个表。明显前者更快一些。

7. 最左前缀原则(***)

  • 多列索引:
    ALTER TABLE people ADD INDEX lname_fname_age (lame,fname,age);
    1. 为了提高搜索效率,我们需要考虑运用多列索引,由于索引文件以B-Tree格式保存,所以我们不用扫描任何记录,即可得到最终结果。
    2. 注:在mysql中执行查询时,只能使用一个索引,如果我们在lname,fname,age上分别建索引,执行查询时,只能使用一个索引,mysql会选择一个最严格(获得结果集记录数最少)的索引。
    3. 最左前缀原则:顾名思义,就是最左优先,上例中我们创建了lname_fname_age多列索引,相当于创建了(lname)单列索引,(lname,fname)组合索引以及(lname,fname,age)组合索引。

二索引

1. 什么是索引?

  • 数据库索引,是数据库管理系统中一个排序的数据结构,索引的实现通常使用B树及其变种B+树。
  • 在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法。这种数据结构,就是索引。

2. 索引的作用?它的优点缺点是什么?

  • 索引作用:
    1. 协助快速查询、更新数据库表中数据。
    2. 为表设置索引要付出代价的:
      • 增加了数据库的存储空间
      • 是在插入和修改数据时要花费较多的时间(因为索引也要随之变动)。

3. 索引的优缺点?

  • 创建索引可以大大提高系统的性能(优点):
    1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
    2. 可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
    3. 可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
    4. 在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
    5. 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。
  • 增加索引也有许多不利的方面(缺点):
    1. 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
    2. 索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。
    3. 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。

4. 哪些列适合建立索引、哪些不适合建索引?

  • 索引是建立在数据库表中的某些列的上面。在创建索引的时候,应该考虑在哪些列上可以创建索引,在哪些列上不能创建索引。
  • 一般来说,应该在这些列上创建索引:
    1. 在经常需要搜索的列上,可以加快搜索的速度;
    2. 在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
    3. 在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;
    4. 在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;
    5. 在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
    6. 在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。
  • 对于有些列不应该创建索引:
    1. 对于那些在查询中很少使用或者参考的列不应该创建索引。这是因为,既然这些列很少使用到,因此有索引或者无索引,并不能提高查询速度。相反,由于增加了索引,反而降低了系统的维护速度和增大了空间需求。
    2. 对于那些只有很少数据值的列也不应该增加索引。这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。
    3. 对于那些定义为text, image和bit数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少。
    4. 当修改性能远远大于检索性能时,不应该创建索引。这是因为,修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因此,当修改性能远远大于检索性能时,不应该创建索引。

5. 什么样的字段适合建索引

唯一、不为空、经常被查询的字段

6. MySQL B+Tree索引和Hash索引的区别?

  • Hash索引和B+树索引的特点:
    1. Hash索引结构的特殊性,其检索效率非常高,索引的检索可以一次定位;
    2. B+树索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问;
  • 为什么不都用Hash索引而使用B+树索引?
    1. Hash索引仅仅能满足"=",“IN"和”"查询,不能使用范围查询,因为经过相应的Hash算法处理之后的Hash值的大小关系,并不能保证和Hash运算前完全一样;
    2. Hash索引无法被用来避免数据的排序操作,因为Hash值的大小关系并不一定和Hash运算前的键值完全一样;
    3. Hash索引不能利用部分索引键查询,对于组合索引,Hash索引在计算Hash值的时候是组合索引键合并后再一起计算Hash值,而不是单独计算Hash值,所以通过组合索引的前面一个或几个索引键进行查询的时候,Hash索引也无法被利用;
    4. Hash索引在任何时候都不能避免表扫描,由于不同索引键存在相同Hash值,所以即使取满足某个Hash键值的数据的记录条数,也无法从Hash索引中直接完成查询,还是要回表查询数据;
    5. Hash索引遇到大量Hash值相等的情况后性能并不一定就会比B+树索引高。
  • 补充:
    1. MySQL中,只有HEAP/MEMORY引擎才显示支持Hash索引。
    2. 常用的InnoDB引擎中默认使用的是B+树索引,它会实时监控表上索引的使用情况,如果认为建立哈希索引可以提高查询效率,则自动在内存中的“自适应哈希索引缓冲区”建立哈希索引(在InnoDB中默认开启自适应哈希索引),通过观察搜索模式,MySQL会利用index key的前缀建立哈希索引,如果一个表几乎大部分都在缓冲池中,那么建立一个哈希索引能够加快等值查询。
    3. B+树索引和哈希索引的明显区别是,如果是等值查询,那么哈希索引明显有绝对优势,因为只需要经过一次算法即可找到相应的键值;当然了,这个前提是,键值都是唯一的。如果键值不是唯一的,就需要先找到该键所在位置,然后再根据链表往后扫描,直到找到相应的数据;
    4. 如果是范围查询检索,这时候哈希索引就毫无用武之地了,因为原先是有序的键值,经过哈希算法后,有可能变成不连续的了,就没办法再利用索引完成范围查询检索;
      同理,哈希索引没办法利用索引完成排序,以及like ‘xxx%’ 这样的部分模糊查询(这种部分模糊查询,其实本质上也是范围查询);
    5. 哈希索引也不支持多列联合索引的最左匹配规则;
    6. B+树索引的关键字检索效率比较平均,不像B树那样波动幅度大,在有大量重复键值情况下,哈希索引的效率也是极低的,因为存在所谓的哈希碰撞问题。
    7. 在大多数场景下,都会有范围查询、排序、分组等查询特征,用B+树索引就可以了。

7. B树和B+树的区别(**)

  1. B树,每个节点都存储key和data,所有节点组成这棵树,并且叶子节点指针为nul,叶子结点不包含任何关键字信息。
  2. B+树,所有的叶子结点中包含了全部关键字的信息,及指向含有这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大的顺序链接,所有的非终端结点可以看成是索引部分,结点中仅含有其子树根结点中最大(或最小)关键字。 (而B 树的非终节点也包含需要查找的有效信息)
  3. 一篇文章讲透MySQL为什么要用B+树实现索引

8. 为什么说B+比B树更适合实际应用中操作系统的文件索引和数据库索引?

  • B+的磁盘读写代价更低
    B+的内部结点并没有指向关键字具体信息的指针。因此其内部结点相对B树更小。如果把所有同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就越多。相对来说IO读写次数也就降低了。
  • B+tree的查询效率更加稳定
    由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。

9. 聚集索引和非聚集索引区别?

  • 聚合索引(clustered index):
    1. 聚集索引表记录的排列顺序和索引的排列顺序一致,所以查询效率快,只要找到第一个索引值记录,其余就连续性的记录在物理也一样连续存放。聚集索引对应的缺点就是修改慢,因为为了保证表中记录的物理和索引顺序一致,在记录插入的时候,会对数据页重新排序。
    2. 聚集索引类似于新华字典中用拼音去查找汉字,拼音检索表于书记顺序都是按照a~z排列的,就像相同的逻辑顺序于物理顺序一样,当你需要查找a,ai两个读音的字,或是想一次寻找多个傻(sha)的同音字时,也许向后翻几页,或紧接着下一行就得到结果了。
  • 非聚合索引(nonclustered index):
    1. 非聚集索引指定了表中记录的逻辑顺序,但是记录的物理和索引不一定一致,两种索引都采用B+树结构,非聚集索引的叶子层并不和实际数据页相重叠,而采用叶子层包含一个指向表中的记录在数据页中的指针方式。非聚集索引层次多,不会造成数据重排。
    2. 非聚集索引类似在新华字典上通过偏旁部首来查询汉字,检索表也许是按照横、竖、撇来排列的,但是由于正文中是a~z的拼音顺序,所以就类似于逻辑地址于物理地址的不对应。同时适用的情况就在于分组,大数目的不同值,频繁更新的列中,这些情况即不适合聚集索引。
  • 根本区别:
    聚集索引和非聚集索引的根本区别是表记录的排列顺序和与索引的排列顺序是否一致。

三、事务

1. 什么是事务?

事务是对数据库中一系列操作进行统一的回滚或者提交的操作,主要用来保证数据的完整性和一致性。

2. 事务四大特性(ACID)原子性、一致性、隔离性、持久性?

  • 原子性(Atomicity):
    原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
  • 一致性(Consistency):
    事务开始前和结束后,数据库的完整性约束没有被破坏。比如A向B转账,不可能A扣了钱,B却没收到。
  • 隔离性(Isolation):
    隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
  • 持久性(Durability):
    持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

3. 事务的并发?事务隔离级别,每个级别会引发什么问题,MySQL默认是哪个级别?

从理论上来说, 事务应该彼此完全隔离, 以避免并发事务所导致的问题,然而, 那样会对性能产生极大的影响, 因为事务必须按顺序运行, 在实际开发中, 为了提升性能, 事务会以较低的隔离级别运行, 事务的隔离级别可以通过隔离事务属性指定。

  • 事务的并发问题

    1. 脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
    2. 不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果因此本事务先后两次读到的数据结果会不一致。
    3. 幻读:幻读解决了不重复读,保证了同一个事务里,查询的结果都是事务开始时的状态(一致性)。
      例如:事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作 这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。 而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有跟没有修改一样,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。
      小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表。
  • 事务的隔离级别

    1. 读未提交:另一个事务修改了数据,但尚未提交,而本事务中的SELECT会读到这些未被提交的数据脏读。
    2. 不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果因此本事务先后两次读到的数据结果会不一致。
    3. 可重复读:在同一个事务里,SELECT的结果是事务开始时时间点的状态,因此,同样的SELECT操作读到的结果会是一致的。但是,会有幻读现象。
    4. 串行化:最高的隔离级别,在这个隔离级别下,不会产生任何异常。并发的事务,就像事务是在一个个按照顺序执行一样。
  • 特别注意:

    1. MySQL默认的事务隔离级别为repeatable-read。
    2. MySQL 支持 4 中事务隔离级别。
    3. 事务的隔离级别要得到底层数据库引擎的支持, 而不是应用程序或者框架的支持。
    4. Oracle 支持的 2 种事务隔离级别:READ_COMMITED , SERIALIZABLE。
    5. SQL规范所规定的标准,不同的数据库具体的实现可能会有些差异。
    6. MySQL中默认事务隔离级别是“可重复读”时并不会锁住读取到的行。
    7. 事务隔离级别:未提交读时,写数据只会锁住相应的行。
    8. 事务隔离级别为:可重复读时,写数据会锁住整张表。
    9. 事务隔离级别为:串行化时,读写数据都会锁住整张表。
    10. 隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大,鱼和熊掌不可兼得啊。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed,它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。

四、存储引擎

1. MySQL常见的三种存储引擎(InnoDB、MyISAM、MEMORY)的区别?

  • 两种存储引擎的大致区别表现在:
    1. InnoDB支持事务,MyISAM不支持, 这一点是非常之重要。事务是一种高级的处理方式,如在一些列增删改中只要哪个出错还可以回滚还原,而MyISAM就不可以了。
    2. MyISAM适合查询以及插入为主的应用。
    3. InnoDB适合频繁修改以及涉及到安全性较高的应用。
    4. InnoDB支持外键,MyISAM不支持。
    5. 从MySQL5.5.5以后,InnoDB是默认引擎。
    6. InnoDB不支持FULLTEXT类型的索引。
    7. InnoDB中不保存表的行数,如select count() from table时,InnoDB需要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count()语句包含where条件时MyISAM也需要扫描整个表。
    8. 对于自增长的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中可以和其他字段一起建立联合索引。
    9. DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的 删除,效率非常慢。MyISAM则会重建表。
    10. InnoDB支持行锁(某些情况下还是锁整表,如 update table set a=1 where user like ‘%lee%’

2. MySQL存储引擎MyISAM与InnoDB如何选择

  • 关于MySQL数据库提供的两种存储引擎,MyISAM与InnoDB选择使用:
    1. INNODB会支持一些关系数据库的高级功能,如事务功能和行级锁,MyISAM不支持。
    2. MyISAM的性能更优,占用的存储空间少,所以,选择何种存储引擎,视具体应用而定。
  • 如果你的应用程序一定要使用事务,毫无疑问你要选择INNODB引擎。但要注意,INNODB的行级锁是有条件的。在where条件没有使用主键时,照样会锁全表。比如DELETE FROM mytable这样的删除语句。
  • 如果你的应用程序对查询性能要求较高,就要使用MyISAM了。MyISAM索引和数据是分开的,而且其索引是压缩的,可以更好地利用内存。所以它的查询性能明显优于INNODB。压缩后的索引也能节约一些磁盘空间。MyISAM拥有全文索引的功能,这可以极大地优化LIKE查询的效率。
  • 有人说MyISAM只能用于小型应用,其实这只是一种偏见。如果数据量比较大,这是需要通过升级架构来解决,比如分表分库,而不是单纯地依赖存储引擎。
  • 现在一般都是选用innodb了,主要是MyISAM的全表锁,读写串行问题,并发效率锁表,效率低,MyISAM对于读写密集型应用一般是不会去选用的。
  • MEMORY存储引擎
    1. MEMORY是MySQL中一类特殊的存储引擎。它使用存储在内存中的内容来创建表,而且数据全部放在内存中。这些特性与前面的两个很不同。
    2. 每个基于MEMORY存储引擎的表实际对应一个磁盘文件。该文件的文件名与表名相同,类型为frm类型。该文件中只存储表的结构。而其数据文件,都是存储在内存中,这样有利于数据的快速处理,提高整个表的效率。值得注意的是,服务器需要有足够的内存来维持MEMORY存储引擎的表的使用。如果不需要了,可以释放内存,甚至删除不需要的表。
    3. MEMORY默认使用哈希索引。速度比使用B型树索引快。当然如果你想用B型树索引,可以在创建索引时指定。
    4. 注意,MEMORY用到的很少,因为它是把数据存到内存中,如果内存出现异常就会影响数据。如果重启或者关机,所有数据都会消失。因此,基于MEMORY的表的生命周期很短,一般是一次性的。

3. MySQL的MyISAM与InnoDB两种存储引擎在,事务、锁级别,各自的适用场景?

  • 事务处理上方面
    1. MyISAM:强调的是性能,每次查询具有原子性,其执行数度比InnoDB类型更快,但是不提供事务支持。
    2. InnoDB:提供事务支持事务,外部键等高级数据库功能。 具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。
  • 锁级别
    1. MyISAM:只支持表级锁,用户在操作MyISAM表时,select,update,delete,insert语句都会给表自动加锁,如果加锁以后的表满足insert并发的情况下,可以在表的尾部插入新的数据。
    2. InnoDB:支持事务和行级锁,是innodb的最大特色。行锁大幅度提高了多用户并发操作的新能。但是InnoDB的行锁,只是在WHERE的主键是有效的,非主键的WHERE都会锁全表的。

五、SQL优化

1. 查询优化(***)

1. SQL查询优化
1. 精确查询字段,不要select *
2. where过滤给经常使用的数据添加索引,精确查询用hash索引,范围查询用B+树索引
3. 数据量有空,有null,或者很少查询,经常修改的字段,不设置索引,因为新建,修改需要更新索引
4. 尽量用join,避免嵌套子查询,数据量大减少子查询(用for循环对比效率后进行替代)
5. 尽量使用索引字段进行连接,过滤,分组,排序
6. 尽量减少having,group_by使用
2. 开启慢查询日志
3. explain 分析SQL
a. id:SELECT查询的序列号,包含一组数字,表示查询中执行SELECT语句或操作表的顺序
b. select_type:简单查询,子查询,union
c. table:显示这一行数据是关于哪张表的
d. type:type显示的是访问类型,是较为重要的一个指标,扫描数据的方式(all,ref,range),得保证查询至少达到range级别,最好能达到ref
e. possible_keys:显示可能应用在这张表中的索引,一个或多个
f. key:实际使用的索引。如果为NULL,则没有使用索引
g. key_len:表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。在不损失精度的情况下,长度越短越好
h. ref:显示索引的哪一列被使用了,哪些列或常量被用于查找索引列上的值
i. rows:根据表统计信息及索引选用情况,大致估算出找到所需记录多需要读取的行数
j. Extra:包含不适合在其他列中显示但十分重要的额外信息(临时表,去重)
4. show profile查询SQL语句在服务器中的执行细节和生命周期
5. SQL数据库服务器参数调优
1. 当order by 和 group by无法使用索引时,增大max_length_for_sort_data参数设置和增大sort_buffer_size参数的设置

正文链接:explain使用+慢SQL分析

2. 大表连小表还是小表连大表?(*)

3. 数据库连接池技术带来的优势?(*)

六、数据库锁

1. mysql都有什么锁,死锁判定原理和具体场景,死锁怎么解决?

  • MySQL有三种锁的级别:页级、表级、行级。
    1. 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
    2. 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
    3. 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般
  • 什么情况下会造成死锁?
    1. 死锁: 是指两个或两个以上的进程在执行过程中。因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等竺的进程称为死锁进程。
    2. 表级锁不会产生死锁.所以解决死锁主要还是针对于最常用的InnoDB。
    3. 死锁的关键在于:两个(或以上)的Session加锁的顺序不一致。
    4. 那么对应的解决死锁问题的关键就是:让不同的session加锁有次序。
  • 死锁的解决办法?
    1. 查出的线程杀死 kill
      SELECT trx_MySQL_thread_id FROM information_schema.INNODB_TRX;
    2. 设置锁的超时时间
      Innodb 行锁的等待时间,单位秒。可在会话级别设置,RDS 实例该参数的默认值为 50(秒)。
  • 生产环境不推荐使用过大的 innodb_lock_wait_timeout参数值
  • 该参数支持在会话级别修改,方便应用在会话级别单独设置某些特殊操作的行锁等待超时时间,如下:set innodb_lock_wait_timeout=1000; —设置当前会话 Innodb 行锁等待超时时间,单位秒。
    1. 指定获取锁的顺序

2. 有哪些锁(乐观锁悲观锁),select 时怎么加排它锁?

  • 悲观锁(Pessimistic Lock):
    1. 悲观锁特点:先获取锁,再进行业务操作。
    2. 即“悲观”的认为获取锁是非常有可能失败的,因此要先确保获取锁成功再进行业务操作。通常所说的“一锁二查三更新”即指的是使用悲观锁。通常来讲在数据库上的悲观锁需要数据库本身提供支持,即通过常用的select … for update操作来实现悲观锁。当数据库执行select for update时会获取被select中的数据行的行锁,因此其他并发执行的select for update如果试图选中同一行则会发生排斥(需要等待行锁被释放),因此达到锁的效果。select for update获取的行锁会在当前事务结束时自动释放,因此必须在事务中使用。
  • 补充:
    1. 不同的数据库对select for update的实现和支持都是有所区别的,
    2. oracle支持select for update no wait,表示如果拿不到锁立刻报错,而不是等待,MySQL就没有no wait这个选项。
    3. MySQL还有个问题是select for update语句执行中所有扫描过的行都会被锁上,这一点很容易造成问题。因此如果在MySQL中用悲观锁务必要确定走了索引,而不是全表扫描。
  • 乐观锁(Optimistic Lock):
    1. 乐观锁,也叫乐观并发控制,它假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,每个事务会先检查在该事务读取数据后,有没有其他事务又修改了该数据。如果其他事务有更新的话,那么当前正在提交的事务会进行回滚。
    2. 乐观锁的特点先进行业务操作,不到万不得已不去拿锁。即“乐观”的认为拿锁多半是会成功的,因此在进行完业务操作需要实际更新数据的最后一步再去拿一下锁就好。
      乐观锁在数据库上的实现完全是逻辑的,不需要数据库提供特殊的支持。
    3. 一般的做法是在需要锁的数据上增加一个版本号,或者时间戳,实现方式举例如下:乐观锁(给表加一个版本号字段) 这个并不是乐观锁的定义,给表加版本号,是数据库实现乐观锁的一种方式。
SELECT data AS old_data, version AS old_version FROM;
# 根据获取的数据进行业务操作,得到new_data和new_version
UPDATE SET data = new_data, version = new_version WHERE version = old_version
if (updated row > 0) {
// 乐观锁获取成功,操作完成
} else {
// 乐观锁获取失败,回滚并重试
}
  • 注意:
    1. 乐观锁在不发生取锁失败的情况下开销比悲观锁小,但是一旦发生失败回滚开销则比较大,因此适合用在取锁失败概率比较小的场景,可以提升系统并发性能
      乐观锁还适用于一些比较特殊的场景,例如在业务操作过程中无法和数据库保持连接等悲观锁无法适用的地方。
  • 总结:
    1. 悲观锁和乐观锁是数据库用来保证数据并发安全防止更新丢失的两种方法,例子在select … for update前加个事务就可以防止更新丢失。悲观锁和乐观锁大部分场景下差异不大,一些独特场景下有一些差别,一般我们可以从如下几个方面来判断。
    2. 响应速度: 如果需要非常高的响应速度,建议采用乐观锁方案,成功就执行,不成功就失败,不需要等待其他并发去释放锁。’
    3. 冲突频率: 如果冲突频率非常高,建议采用悲观锁,保证成功率,如果冲突频率大,乐观锁会需要多次重试才能成功,代价比较大。
    4. 重试代价: 如果重试代价大,建议采用悲观锁。

七 数据库运维

1. 数据库的主从复制

  • 主从复制的几种方式:
    1. 同步复制:
      所谓的同步复制,意思是master的变化,必须等待slave-1,slave-2,…,slave-n完成后才能返回。 这样,显然不可取,也不是MySQL复制的默认设置。比如,在WEB前端页面上,用户增加了条记录,需要等待很长时间。
    2. 异步复制:
      如同AJAX请求一样。master只需要完成自己的数据库操作即可。至于slaves是否收到二进制日志,是否完成操作,不用关心,MySQL的默认设置。
    3. 半同步复制:
      master只保证slaves中的一个操作成功,就返回,其他slave不管。 这个功能,是由google为MySQL引入的。

2. 数据库主从复制分析的 7 个问题?

  1. 问题1:master的写操作,slaves被动的进行一样的操作,保持数据一致性,那么slave是否可以主动的进行写操作?
    假设slave可以主动的进行写操作,slave又无法通知master,这样就导致了master和slave数据不一致了。因此slave不应该进行写操作,至少是slave上涉及到复制的数据库不可以写。实际上,这里已经揭示了读写分离的概念。
  2. 问题2:主从复制中,可以有N个slave,可是这些slave又不能进行写操作,要他们干嘛?
    • 实现数据备份: 类似于高可用的功能,一旦master挂了,可以让slave顶上去,同时slave提升为master。
    • 异地容灾:比如master在北京,地震挂了,那么在上海的slave还可以继续。
    • 主要用于实现scale out,分担负载,可以将读的任务分散到slaves上。
    • 很可能的情况是,一个系统的读操作远远多于写操作,因此写操作发向master,读操作发向slaves进行操作
  3. 问题3:主从复制中有master,slave1,slave2,…等等这么多MySQL数据库,那比如一个JAVA WEB应用到底应该连接哪个数据库?
    • 我们在应用程序中可以这样,insert/delete/update这些更新数据库的操作,用connection(for master)进行操作,
    • select用connection(for slaves)进行操作。那我们的应用程序还要完成怎么从slaves选择一个来执行select,例如使用简单的轮循算法。
    • 这样的话,相当于应用程序完成了SQL语句的路由,而且与MySQL的主从复制架构非常关联,一旦master挂了,某些slave挂了,那么应用程序就要修改了。能不能让应用程序与MySQL的主从复制架构没有什么太多关系呢?
    • 找一个组件,application program只需要与它打交道,用它来完成MySQL的代理,实现SQL语句的路由。
    • MySQL proxy并不负责,怎么从众多的slaves挑一个?可以交给另一个组件(比如haproxy)来完成。
    • 这就是所谓的MySQL READ WRITE SPLITE,MySQL的读写分离。
  4. 问题4:如果MySQL proxy , direct , master他们中的某些挂了怎么办?
    总统一般都会弄个副总统,以防不测。同样的,可以给这些关键的节点来个备份。
  5. 问题5:当master的二进制日志每产生一个事件,都需要发往slave,如果我们有N个slave,那是发N次,还是只发一次?如果只发一次,发给了slave-1,那slave-2,slave-3,…它们怎么办?
    显 然,应该发N次。实际上,在MySQL master内部,维护N个线程,每一个线程负责将二进制日志文件发往对应的slave。master既要负责写操作,还的维护N个线程,负担会很重。可以这样,slave-1是master的从,slave-1又是slave-2,slave-3,…的主,同时slave-1不再负责select。 slave-1将master的复制线程的负担,转移到自己的身上。这就是所谓的多级复制的概念。
  6. 问题6:当一个select发往MySQL proxy,可能这次由slave-2响应,下次由slave-3响应,这样的话,就无法利用查询缓存了。
    应该找一个共享式的缓存,比如memcache来解决。将slave-2,slave-3,…这些查询的结果都缓存至mamcache中。
  7. 问题7:随着应用的日益增长,读操作很多,我们可以扩展slave,但是如果master满足不了写操作了,怎么办呢?
    • scale on ?更好的服务器? 没有最好的,只有更好的,太贵了。。。
    • scale out ? 主从复制架构已经满足不了。
    • 可以分库【垂直拆分】,分表【水平拆分】。

3. mysql 高并发环境解决方案?

  • MySQL 高并发环境解决方案: 分库 分表 分布式 增加二级缓存。。。。。
  • 需求分析:互联网单位 每天大量数据读取,写入,并发性高。
  • 现有解决方式:水平分库分表,由单点分布到多点数据库中,从而降低单点数据库压力。
  • 集群方案:解决DB宕机带来的单点DB不能访问问题。
  • 读写分离策略:极大限度提高了应用中Read数据的速度和并发量。无法解决高写入压力。

正文链接史上最全的数据库面试题,不看绝对后悔

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值