Java 最常见的 面试题 ➕ 答案 十七(MySql)

十七、MySql

1、数据库的三范式是什么?

范式:简言之就是,数据库设计对数据的存储性能,还有开发人员对数据的操作都有莫大的关系。所以建立科学的,规范的的数据库是需要满足一些规范的来优化数据数据存储方式。在关系型数据库中这些规范就可以称为范式。

  1. 第一范式:当关系模式R的所有属性都不能在分解为更基本的数据单位时,称R是满足第一范式的,简记为1NF。满足第一范式是关系模式规范化的最低要求,否则,将有很多基本操作在这样的关系模式中实现不了。
  2. 第二范式:如果关系模式R满足第一范式,并且R得所有非主属性都完全依赖于R的每一个候选关键属性,称R满足第二范式,简记为2NF。
  3. 第三范式:设R是一个满足第一范式条件的关系模式,X是R的任意属性集,如果X非传递依赖于R的任意一个候选关键字,称R满足第三范式,简记为3NF。

2、一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 mysql 数据库,又插入了一条数据,此时 id 是几?

一般情况下,我们创建的表的类型是InnoDB,如果新增一条记录(不重启mysql的情况下),这条记录的id是8;但是如果重启(文中提到的)MySQL的话,这条记录的ID是6。因为InnoDB表只把自增主键的最大ID记录到内存中,所以重启数据库或者对表OPTIMIZE操作,都会使最大ID丢失。

但是,如果我们使用表的类型是MylSAM,那么这条记录的ID就是8。因为MylSAM表会把自增主键的最大ID记录到数据文件里面,重启MYSQL后,自增主键的最大ID也不会丢失。

注:如果在这7条记录里面删除的是中间的几个记录(比如删除的是3,4两条记录),重启MySQL数据库后,insert一条记录后,ID都是8。因为内存或者数据库文件存储都是自增主键最大ID

3、如何获取当前数据库版本?

select version();

4、说一下 ACID 是什么?

ACID:是指数据库事务的ACID,一个事务一般是指多个操作的集合,比如插入数据库分两段插入,第二次插入错误,第一次插入操作也需要回退;

ACID的翻译

  1. Atomicity 原子性:指的是整个事务是一个独立的单元,要么操作成功,要么操作不成功
  2. Consistency 一致性:事务必须要保持和系统处于一致的状态(如果不一致会导致系统其它的方出现bug)
  3. Isolation 隔离性:事务是并发控制机制,他们的交错也需要一致性,隔离隐藏,一般通过悲观或者乐观锁实现
  4. Durability 耐久性:一个成功的事务将永久性地改变系统的状态,所以在它结束之前,所有导致状态的变化都记录在一个持久的事务日志中

5、char 和 varchar 的区别是什么?

  1. char的长度是不可变的,而varchar的长度是可变的
    1. 字段b:类型char(10),     值为:abc,存储为:abc             (abc+7个空格)
    2. 字段d:类型varchar(10), 值为:abc,存储为:abc (自动变为3个的长度)
  2. 超出长度自动截取
    1. 字段c:类型char(3),     值为:abcdefg,存储为:abc(defg自动删除)
    2. 字段e:类型varchar(3), 值为:abcdefg,存储为:abc (defg自动删除)
  3. var(10)和char(10),都表示可存10个字符,无论存放的是数字、字母还是UTF8汉字(每个汉字3字节),都可以存放10个
  4. char最多可以存放255个字符
    1. varchar的最大长度为65535个字节,varchar可存放的字符数跟编码有关
    2. 字符类型若为gbk,每个字符最多占2个字节,最大长度不能超过32766个字符
    3. 字符类型若为utf8,每个字符最多占3个字节,最大长度不能超过21845个字符
  5. char和varchar的最大长度限制是mysql规定的

6、MySQL Float、Double 和 Decimal 的区别?

MySQL中存在float,double等非标准数据类型,也有decimal这种标准数据类型。

其区别在于,float,double等非标准类型,在DB中保存的是近似值,而Decimal则以字符串的形式保存数值。
float,double类型是可以存浮点数(即小数类型),但是float有个坏处,当你给定的数据是整数的时候,那么它就以整数给你处理。这样我们在存取货币值的时候自然遇到问题,我的default值为:0.00而实际存储是0,同样我存取货币为12.00,实际存储是12。
幸好mysql提供了两个数据类型:decimal,这种数据类型可以轻松解决上面的问题:decimal类型被 MySQL 以同样的类型实现,这在 SQL92 标准中是允许的。他们用于保存对准确精度有重要要求的值,例如与金钱有关的数据。

默认状态比较:浮点数如果不写经度和标度,会按照实际精度值保存,如果有精度和标度,则会自动将四舍五入后的结果插入,系统不会报错;定点数如果不写精度和标度,则按照默认值decimal(10,0) 来操作,如果数据超过了精度和标度值,系统会报错。

7、mysql 的内连接、左连接、右连接有什么区别?

  1. 内连接:显示两个表中有联系的所有数据;
  2. 左链接:以左表为参照,显示所有数据,右表中没有则以null显示
  3. 右链接:以右表为参照显示数据,,左表中没有则以null显示

8、mysql 索引是怎么实现的?

索引本质:MySQL存储引擎使用索引的方法,类似于读一本书时如果想查找特定的主题的话,需要先看书的目录,查找对应的页码,翻到指定页码查看内容。即首先在索引中查找对应索引值,然后根据索引记录查找对应的数据行。MySQL支持多种索引,例如B树索引、哈希索引、全文索引等。

B-tree索引:相当于金字塔大树分支 例如1000条数据 也就10多行 那么查询也只需要10多次。独立索引只能用一个。

hash索引: 一对一主键 不利于范围查询 无法利用前缀查询,所谓Hash索引,当我们要给某张表某列增加索引时,将这张表的这一列进行哈希算法计算,得到哈希值,排序在哈希数组上。所以Hash索引可以一次定位,其效率很高,而Btree索引需要经过多次的磁盘IO,但是innodb和myisam之所以没有采用它,是因为它存在着好多缺点:

  1. 因为Hash索引比较的是经过Hash计算的值,所以只能进行等式比较,不能用于范围查询
  2. 每次都要全表扫描
  3. 由于哈希值是按照顺序排列的,但是哈希值映射的真正数据在哈希表中就不一定按照顺序排列,所以无法利用Hash索引来加速任何排序操作
  4. 不能用部分索引键来搜索,因为组合索引在计算哈希值的时候是一起计算的。
  5. 当哈希值大量重复且数据量非常大时,其检索效率并没有Btree索引高的。

Btree索引:至于Btree索引,它是以B+树为存储结构实现的。但是Btree索引的存储结构在Innodb和MyISAM中有很大区别。在MyISAM中,我们如果要对某张表的某列建立Btree索引的话,所以我们经常会说MyISAM中数据文件和索引文件是分开的。因此MyISAM的索引方式也称为非聚集,Innodb的索引方式成为聚集索引。至于辅助索引,类似于主索引,唯一区别就是主索引上的值不能重复,而辅助索引可以重复。因此当我们根据Btree索引去搜索的时候,若key存在,在data域找到其地址,然后根据地址去表中查找数据记录。至于Innodb它跟上面又有很大不同,它的叶子节点存储的并不是表的地址,而是数据我们可以看到这里并没有将地址放入叶子节点,而是直接放入了对应的数据,这也就是我们平常说到的,Innodb的索引文件就是数据文件,那么对于Innodb的辅助索引结构跟主索引也相差很多

9、怎么验证 mysql 的索引是否满足需求?

使用 explain 查看 SQL 是如何执行查询语句的,从而分析你的索引是否满足需求。 explain 语法:explain select * from table where type=1。

10、说一下数据库的事务隔离?

为了解决“隔离”与“并发”的矛盾,ISO/ANSI SQL92定义了4个事务隔离级别,每个级别的隔离程度不同,允许出现的副作用也不同,应用可以根据自己的业务逻辑要求,通过选择不同的隔离级别来平衡 “隔离”与“并发”的矛盾。

4个事务隔离级别:

  • Read uncommitted (读未提交):最低级别,以上问题均无法解决。
  • Read committed (读已提交):读已提交,可避免脏读情况发生。
  • Repeatable Read(可重复读):确保事务可以多次从一个字段中读取相同的值,在此事务持续期间,禁止其他事务对此字段的更新,可以避免脏读和不可重复读,仍会出现幻读问题。
  • Serializable (串行化):最严格的事务隔离级别,要求所有事务被串行执行,不能并发执行,可避免脏读、不可重复读、幻读情况的发生。

这四种隔离级别,分别有可能产生问题总结如下:
在这里插入图片描述

很多人容易搞混不可重复读和幻读,确实这两者有些相似。但不可重复读重点在于update和delete,而幻读的重点在于insert。避免不可重复读需要锁行(某一行在select操作时,不允许update与delete)就行,避免幻读则需要锁表。如果使用锁机制来实现这两种隔离级别,在可重复读中,该sql第一次读取到数据后,就将这些数据加锁,其它事务无法修改这些数据,就可以实现可重复读了。但这种方法却无法锁住insert的数据,所以当事务A先前读取了数据,或者修改了全部数据,事务B还是可以insert数据提交,这时事务A就会发现莫名其妙多了一条之前没有的数据,幻读不能通过行锁来避免,需要Serializable隔离级别 ,读用读锁,写用写锁,读锁和写锁互斥,这么做可以有效的避免幻读、不可重复读、脏读等问题,但会极大的降低数据库的并发能力。所以说不可重复读和幻读最大的区别,就在于如何通过锁机制来解决他们产生的问题。

以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当然隔离级别越高,越能保证数据的完整性和统一性,但是执行效率就越低,对并发性能的影响也越大。像Serializable这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。

各类流行的数据库都实现了一些SQL标准中的事务隔离级别,但是他们的实现也是极其不一样的。Oracle仅仅实现了RC 和 SERIALIZABLE隔离级别。默认采用RC隔离级别,解决了脏读。但是允许不可重复读和幻读。其SERIALIZABLE则解决了脏读、不可重复读、幻读。MySQL支持全部4个隔离级别,但在具体实现时,有一些特点,比如在一些隔离级别下是采用MVCC一致性读,但某些情况下又不是。MySQL默认采用RR隔离级别,SQL标准是要求RR解决不可重复读的问题,但是因为MySQL通过nex-key lock在RR隔离级别下解决了幻读的问题。那么MySQL的SERIALIZABLE是怎么回事呢?MySQL的SERIALIZABLE采用了经典的实现方式,对读和写都加锁。

11、说一下 mysql 常用的引擎?

MySQL常用的四种引擎:

  1. MyISAM存储引擎:不支持事务、也不支持外键,优势是访问速度快,对事务完整性没有 要求或者以select,insert为主的应用基本上可以用这个引擎来创建表;支持3种不同的存储格式,分别是:静态表;动态表;压缩表
    1. 静态表:表中的字段都是非变长字段,这样每个记录都是固定长度的,优点存储非常迅速,容易缓存,出现故障容易恢复;缺点是占用的空间通常比动态表多(因为存储时会按照列的宽度定义补足空格)ps:在取数据的时候,默认会把字段后面的空格去掉,如果不注意会把数据本身带的空格也会忽略。
    2. 动态表:记录不是固定长度的,这样存储的优点是占用的空间相对较少;缺点:频繁的更新、删除数据容易产生碎片,需要定期执行OPTIMIZE TABLE或者myisamchk-r命令来改善性能
    3. 压缩表:因为每个记录是被单独压缩的,所以只有非常小的访问开支
  2. InnoDB存储引擎*:该存储引擎提供了具有提交、回滚和崩溃恢复能力的事务安全。但是对比MyISAM引擎,写的处理效率会差一些,并且会占用更多的磁盘空间以保留数据和索引。 InnoDB存储引擎的特点:支持自动增长列,支持外键约束
  3. MEMORY存储引擎:
    1. Memory存储引擎使用存在于内存中的内容来创建表。每个memory表只实际对应一个磁盘文件,格式是.frm。memory类型的表访问非常的快,因为它的数据是放在内存中的,并且默认使用HASH索引,但是一旦服务关闭,表中的数据就会丢失掉。 
    2. MEMORY存储引擎的表可以选择使用BTREE索引或者HASH索引,两种不同类型的索引有其不同的使用范围
    3. Hash索引优点: Hash 索引结构的特殊性,其检索效率非常高,索引的检索可以一次定位,不像B-Tree 索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问,所以 Hash 索引的查询效率要远高于 B-Tree 索引。 
    4. Hash索引缺点: 那么不精确查找呢,也很明显,因为hash算法是基于等值计算的,所以对于“like”等范围查找hash索引无效,不支持;
    5. Memory类型的存储引擎主要用于哪些内容变化不频繁的代码表,或者作为统计操作的中间结果表,便于高效地对中间结果进行分析并得到最终的统计结果,。对存储引擎为memory的表进行更新操作要谨慎,因为数据并没有实际写入到磁盘中,所以一定要对下次重新启动服务后如何获得这些修改后的数据有所考虑。
  4. MERGE存储引擎:Merge存储引擎是一组MyISAM表的组合,这些MyISAM表必须结构完全相同,merge表本身并没有数据,对merge类型的表可以进行查询,更新,删除操作,这些操作实际上是对内部的MyISAM表进行的。

12、说一下 mysql 的行锁和表锁?

MyISAM 只支持表锁,InnoDB 支持表锁和行锁,默认为行锁。 表级锁:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发量最低。 行级锁:开销大,加锁慢,会出现死锁。锁力度小,发生锁冲突的概率小,并发度最高。

13、说一下乐观锁和悲观锁?

  • 乐观锁:每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。
  • 悲观锁:每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻止,直到这个锁被释放。
  • 数据库的乐观锁需要自己实现,在表里面添加一个 version 字段,每次修改成功值加 1,这样每次修改的时候先对比一下,自己拥有的 version 和数据库现在的 version 是否一致,如果不一致就不修改,这样就实现了乐观锁。

14、mysql 问题排查都有哪些手段?

  • 可以使用 show processlist 命令查看当前所有连接信息。
  • 使用 explain 命令查询 SQL 语句执行计划。
  • 开启慢查询日志,查看慢查询的 SQL。

15、如何做 mysql 的性能优化?

  1. Scheme设计与数据类型优化:
    1. 选择数据类型只要遵循小而简单的原则就好,越小的数据类型通常会更快,占用更少的磁盘、内存,处理时需要的CPU周期也更少。
    2. 越简单的数据类型在计算时需要更少的CPU周期,比如,整型就比字符操作代价低,因而会使用整型来存储ip地址,使用DATETIME来存储时间,而不是使用字符串。
  2. 创建高性能索引:
    1. 索引是提高MySQL查询性能的一个重要途径,但过多的索引可能会导致过高的磁盘使用率以及过高的内存占用,从而影响应用程序的整体性能。应当尽量避免事后才想起添加索引,因为事后可能需要监控大量的SQL才能定位到问题所在,而且添加索引的时间肯定是远大于初始添加索引所需要的时间,可见索引的添加也是非常有技术含量的。
    2. 在设计索引时,如果一个索引既能够满足排序,又满足查询,是最好的。创建索引需要注意的技巧:
      1. 索引创建要覆盖查询条件
      2. 使用索引扫描来排序
      3. 删除长期未使用的索引
      4. 索引在like里面的使用注意事项
      5. 对于使用like的查询,查询如果是 ‘%aaa’ 不会使用到索引,‘aaa%’ 会使用到索引。
  3. 建表永远要留一个ID主键:同时建表也要注意遵守以下几个范式
    1. Java 最常见的 面试题 ➕ 答案 十七(MySql)_第1张图片
  4. 分析查询日志和慢查询日志
    1. 记录全部查询。这在用 ORM 系统或者生成查询语句的系统非常实用:log=/var/log/mysql.log
    2. 注意千万不要在生产环境用。否则日志会占满你的磁盘空间。后果不堪设想。
    3. 记录运行时间超过 2秒的查询:long_query_time=2
    4. log-slow-queries=/var/log/mysql/log-slow-queries.log

  5. 尽量不要使用NOT IN和<>操作

  6. 尽量避免Select * 命令
  7. 尽量不要使用BY RAND()命令
  8. 尽量少排序
  9. 尽量少OR

 

 

注:以上内容仅提供参考和交流,请勿用于商业用途,如有侵权联系本人删除!

注:此博客只是为了记忆相关知识点,大部分为网络上的文章,在此向各个文章的作者表示感谢!

你可能感兴趣的:(面试题,java,面试)