Mysql常见面试题总结

文章详细介绍了MySQL中的存储引擎,如InnoDB和MyISAM的特性、区别及适用场景,还涉及数据库设计的三大范式及其优缺点。此外,阐述了一条SQL语句的执行流程,并提到了MySQL的优化方法,包括索引、分区、缓存等。文章最后讨论了MySQL的日志系统,如binlog和redolog的作用,以及如何处理大数据量表的优化策略。
摘要由CSDN通过智能技术生成

1、什么是存储引擎

        存储引擎指定了表的类型,即如何存储和索引数据,是否支持事务,同时存储引擎也决定了表在计算机中的存储方式。

2、查看数据库支持哪些存储引擎使用什么命令?

-- 查看数据库支持的存储引擎
show engines;
或者
show variables like 'have%';

-- 查看当前默认的存储引擎
show variables like 'storage_engine%';

3、MySQL常见的存储引擎有哪些?

        MySQL中常用的四种存储引擎分别是: MyISAMInnoDBMEMORYARCHIVE

InnoDB存储引擎

InnoDB是MySQL默认的事务型存储引擎,使用最广泛,基于聚簇索引建立的。InnoDB内部做了很多优化,如能够自动在内存中创建自适应hash索引,以加速读操作。
优点:支持事务和崩溃修复能力;引入了行级锁和外键约束。
缺点:占用的数据空间相对较大。
适用场景:需要事务支持,并且有较高的并发读写频率。

MyISAM存储引擎

数据以紧密格式存储。对于只读数据,或者表比较小、可以容忍修复操作,可以使用MyISAM引擎。MyISAM会将表存储在两个文件中,数据文件.MYD和索引文件.MYI。
优点:访问速度快。
缺点:MyISAM不支持事务和行级锁,不支持崩溃后的安全恢复,也不支持外键。
适用场景:对事务完整性没有要求;表的数据都会只读的。

MEMORY存储引擎

MEMORY引擎将数据全部放在内存中,访问速度较快,但是一旦系统奔溃的话,数据都会丢失,MEMORY引擎默认使用哈希索引,将键的哈希值和指向数据行的指针保存在哈希索引中。
优点:访问速度较快。
缺点:哈希索引数据不是按照索引值顺序存储,无法用于排序。不支持部分索引匹配查找,因为哈希索引是使用索引列的全部内容来计算哈希值的。只支持等值比较,不支持范围查询。当出现哈希冲突时,存储引擎需要遍历链表中所有的行指针,逐行进行比较,直到找到符合条件的行。

ARCHIVE存储引擎

ARCHIVE存储引擎非常适合存储大量独立的、作为历史记录的数据。ARCHIVE提供了压缩功能,拥有高效的插入速度,但是这种引擎不支持索引,所以查询性能较差。

4、MyISAM与InnoDB的区别

  1. InnoDB支持事务,MyISAM不支持。
  2. InnoDB支持外键, MyISAM不支持。
  3. InnoDB使用的是聚集索引,MyISAM是非聚集索引。
  4. InnoDB支持 MVCC(多版本并发控制),MyISAM 不支持。
  5. InnoDB支持行级锁和表级锁,默认为行级锁,(某些情况下还是锁整表,如 update table set a=1 where user like '%lee%'),MyISAM 只有表级锁。
  6. Innodb不支持FULLTEXT全文索引(5.6以后也支持了),而MyISAM支持全文索引。
  7. InnoDB表必须有主键,而MyISAM可以没有主键。
  8. InnoDB中不保存表的行数,如select count(*) from table时,InnoDB需要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count(*)语句包含where条件时MyISAM也需要扫描整个表。
  9. select count(*) from table时,MyISAM更快,因为它有一个变量保存了整个表的总行数,可以直接读取,InnoDB就需要全表扫描。
  10. InnoDB适合频繁修改以及涉及到安全性较高的应用,MyISAM适合查询以及插入为主的应用。
  11. 对于自增长的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中可以和其他字段一起建立联合索引
  12. InnoDB按主键大小有序插入,MyISAM记录插入顺序,按记录插入顺序保存。
  13. InnoDB表需要更多的内存和存储,而MyISAM可被压缩,存储空间较小。
  14. 清空整个表时,InnoDB是一行一行的删除,效率非常慢,MyISAM则会重建表。
  15. InnoDB 存储引擎提供了具有提交、回滚、崩溃恢复能力的事务安全,与 MyISAM 比 InnoDB 写的效率差一些,并且会占用更多的磁盘空间以保留数据和索引。
  16. InnoDB主键索引采用聚集索引,B+树叶子存储数据,MyISAM采用非聚集索引,B+树叶子存储指向数据文件的指针。

适用场景:

  • MyISAM适合:插入不频繁,查询非常频繁,如果执行大量的SELECT,MyISAM是更好的选择, 没有事务。
  • InnoDB适合:可靠性要求比较高,或者要求事务;表更新和查询都相当的频繁, 大量的INSERT或UPDATE

  5、数据库设计的三大范式是什么?优缺点是什么?

第一范式1NF:确保数据库表字段的原子性,1NF是对属性的原子性约束,要求属性具有原子性,不可再分解,数据表中的每一列(每个字段)都不可以再拆分。

例:字段 userInfo广东省 10086' ,依照第一范式必须拆分成 userInfo广东省 userTel:10086两个字段。

第二范式2NF:首先要满足第一范式,另外包含两部分内容,一是表必须有一个主键;二是非主键列必须完全依赖于主键,而不能只依赖于主键的一部分。2NF是对记录的惟一性约束,要求记录有惟一标识,即实体的惟一性;

例:假定选课关系表为student_course(student_no, student_name, age, course_name, grade, credit),主键为(student_no, course_name)。其中学分完全依赖于课程名称,姓名年龄完全依赖学号,不符合第二范式,会导致数据冗余(学生选n门课,姓名年龄有n条记录)、插入异常(插入一门新课,因为没有学号,无法保存新课记录)等问题。

可以拆分成三个表:学生:student(stuent_no, student_name, 年龄);课程:course(course_name, credit);选课关系:student_course_relation(student_no, course_name, grade)。

第三范式3NF:首先要满足第二范式,另外非主键列必须直接依赖于主键,不能存在传递依赖。即不能存在:非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况。3NF是对字段冗余性的约束,即任何字段不能由其他字段派生出来,它要求字段没有冗余。

假定学生关系表为Student(student_no, student_name, age, academy_id, academy_telephone),主键为"学号",其中学院id依赖于学号,而学院地点和学院电话依赖于学院id,存在传递依赖,不符合第三范式。

可以把学生关系表分为如下两个表:学生:(student_no, student_name, age, academy_id);学院:(academy_id, academy_telephone)。

2NF和3NF的区别?

  • 2NF依据是非主键列是否完全依赖于主键,还是依赖于主键的一部分。
  • 3NF依据是非主键列是直接依赖于主键,还是直接依赖于非主键。

三范式化设计的优缺点:

优点:可以尽量得减少数据冗余,使得更新快,体积小
缺点:对于查询需要多个表进行关联,减少写得效率增加读得效率,更难进行索引优化。

6、讲一下MySQL架构?

参考:一条SQL语句在Mysql中是如何执行的

MySQL主要分为 Server 层和存储引擎层:

  • Server 层:主要包括连接器、查询缓存、分析器、优化器、执行器等,所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图,函数等,还有一个通用的日志模块 binglog 日志模块。
  • 存储引擎: 主要负责数据的存储和读取。server 层通过api与存储引擎进行通信。

Server 层基本组件

  • 连接器: 当客户端连接 MySQL 时,server层会对其进行身份认证和权限校验。
  • 查询缓存(MySQL8.0以后的版本移除了此功能): 执行查询语句的时候,会先查询缓存,先校验这个 sql 是否执行过,如果有缓存这个 sql,就会直接返回给客户端,如果没有命中,就会执行后续的操作。
  • 分析器: 没有命中缓存的话,SQL 语句就会经过分析器,主要分为两步,词法分析和语法分析,先看 SQL 语句要做什么,再检查 SQL 语句语法是否正确。
  • 优化器: 优化器对查询进行优化,包括重写查询、决定表的读写顺序以及选择合适的索引等,生成执行计划。
  • 执行器: 首先执行前会校验该用户有没有权限,如果没有权限,就会返回错误信息,如果有权限,就会根据执行计划去调用引擎的接口,返回结果。

7、一条SQL语句在MySQL中是如何执行的?

 参考:一条SQL语句在Mysql中是如何执行的

查询语句的执行流程:连接器权限校验---》查询缓存---》分析器---》优化器---》权限校验---》执行器---》引擎。

例:select from user where id > 1 and name '大彬';

  • 首先连接器检查权限,没有权限则返回错误;
  • MySQL8.0以前会查询缓存,缓存命中则直接返回,没有则执行下一步;
  • 分析器进行词法分析和语法分析。提取表名、查询条件,检查语法是否有错误;
  • 两种执行方案,先查 id > 1 还是 name = '大彬',优化器根据自己的优化算法选择执行效率最好的方案;
  • 校验权限,有权限就调用数据库引擎接口,返回引擎的执行结果。

更新语句的执行流程:分析器、权限校验、执行器、引擎、redo logprepare状态)、binlogredo logcommit状态)

例:update user set name '大彬' where id = 1;

  • 先查询到 id 为1的记录,有缓存会使用缓存。
  • 拿到查询结果,将 name 更新为大彬,然后调用引擎接口,写入更新数据,innodb 引擎将数据保存在内存中,同时记录redo log,此时redo log进入 prepare状态。
  • 执行器收到通知后记录binlog,然后调用引擎接口,提交redo log为commit状态。
  • 更新完成。

为什么记录完redo log,不直接提交,而是先进入prepare状态?

假设先写redo log直接提交,然后写binlog,写完redo log后,机器挂了,binlog日志没有被写入,那么机器重启后,这台机器会通过redo log恢复数据,但是这个时候binlog并没有记录该数据,后续进行机器备份的时候,就会丢失这一条数据,同时主从同步也会丢失这一条数据。

8、MySQL的常用日志文件有哪些?

        MySQL日志主要包括查询日志、慢查询日志、事务日志、错误日志、二进制日志等。其中比较重要的是 bin log(二进制日志)和 redo log(重做日志)和 undo log(回滚日志)。

bin log(二进制日志)

        bin log是MySQL数据库级别的文件,记录对MySQL数据库执行修改的所有操作,不会记录select和show语句,主要用于恢复数据库和同步数据库,数据库主从同步就是基于此日志文件。

redo log(重做日志)

        redo log是innodb引擎级别,用来记录innodb存储引擎的事务日志,不管事务是否提交都会记录下来,用于数据恢复。当数据库发生故障,innoDB存储引擎会使用redo log恢复到发生故障前的时刻,以此来保证数据的完整性。将参数innodb_flush_log_at_tx_commit设置为1,那么在执行commit时会将redo log同步写到磁盘。

undo log(回滚日志)

        除了记录redo log外,当进行数据修改时还会记录undo log,undo log用于数据的撤回操作,它保留了记录修改前的内容。通过undo log可以实现事务回滚,并且可以根据undo log回溯到某个特定的版本的数据,实现MVCC。

9、bin log和redo log有什么区别?

  • bin log会记录所有日志记录,包括InnoDB、MyISAM等存储引擎的日志;redo log只记录innoDB自身的事务日志。
  • bin log只在事务提交前写入到磁盘,一个事务只写一次;而在事务进行过程,会有redo log不断写入磁盘。
  • bin log是逻辑日志,记录的是SQL语句的原始逻辑;redo log是物理日志,记录的是在某个数据页上做了什么修改。

10、近千万条数据的大表怎么优化?

        当MySQL单表记录数过大时,数据库的性能会明显下降,一些常见的优化措施如下:

  • 限定数据的范围。比如:用户在查询历史信息的时候,可以控制在一个月的时间范围内;
  • 读写分离: 经典的数据库拆分方案,主库负责写,从库负责读;
  • 通过分库分表的方式进行优化,主要有垂直拆分和水平拆分。

11、日常工作中你是怎么优化SQL的?

可以从这几个维度回答这个问题:

  • 加索引
  • 避免返回不必要的数据
  • 适当分批量进行
  • 优化sql结构
  • 分库分表
  • 读写分离
  • 系统配置的优化
  • 硬件的优化

12、MySQL数据库一天五万条以上的增量,预计运维三年,怎么优化? 

  • 设计良好的数据库结构,允许部分数据冗余,尽量避免join查询,提高效率。
  • 选择合适的表字段数据类型和存储引擎,适当的添加索引。
  • mysql库主从读写分离。
  • 找规律分表,减少单表中的数据量提高查询速度。
  • 添加缓存机制,比如memcached,redis等。
  • 不经常改动的页面,生成静态页面。
  • 书写高效率的SQL。比如 SELECT * FROM TABEL 改为 SELECT field_1, field_2, field_3 FROM TABLE.

13、MySQL常用的聚合函数有哪些?

  • count() 获取记录条数
  • avg(col)  获取指定列的平均值
  • sum(col) 求和
  • max(col) 获取指定列的最大值
  • min(col) 获取指定列的最小值

14、Mysql 中有哪几种锁

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

15、如何开启mysql慢查询日志

# 在 mysql的安装配置文件my.cnf中【mysqlid】位置处设置参数,然后重启【永久有效】,my.cnf
的位置一般再/etc/my.cnf 

# 常用参数:
slow_query_log = "ON" # 是否开启慢查询日志,默认OFF,开启则设置为 ON。
slow_query_log_file = "/mydata/mysqllog/slowquery.log" # 慢查询日志文件存储位置(绝对路径)。
log-slow-queries = /var/lib/mysql/slowquery.log (指定日志文件存放位置,可以为空,系统会给一个缺省的文件host_name-slow.log)

log_queries_not_using_indexes = "ON" # 是否把没有使用到索引的SQL记录到日志中,默认OFF,开启则设置为 ON。
long_query_time = 2 # 超过多少秒的查询才会记录到日志中,注意单位是秒, 默认是10秒。

20、你使用过哪些类型的主键?

        常用的主键有三种:用的最多的是自增ID、还有uuid、雪花ID等 。如果是数据量不是很大的情况下不需要分库分表的时,使用自增ID为主键最合适。如果是分布式存储(分库、分表等)就要考虑使用uuid做主键,可以对其进行改造变成有序的uuid既可。

21、自增ID主键的优缺点

优点:

  • 主键页以近乎顺序的方式填写,提升了页的利用率
  • 索引更加紧凑,性能更好,查询时数据访问更快
  • 节省磁盘空间。500W数据,UUID占5.4G,自增ID占2.5G.
  • 连续增长的值能避免 b+ 树频繁合并和分裂
  • 简单易懂,几乎所有数据库都支持自增类型

缺点:

  • 可靠性不高:存在自增ID回溯的问题,这个问题直到最新版本的MySQL 8.0才修复。
  • 安全性不高:ID不够随机,对外暴露的接口可以非常容易猜测对应的信息。比如:/User/1/这样的接口,可以非常容易猜测用户ID的值为多少,总用户数量有多少(泄露发号数量的信息),也可以非常容易地通过接口进行数据的爬取,因此不太安全。
  • 局部唯一性:最重要的一点,自增ID是局部唯一,只在当前数据库实例中唯一,而不是全局唯一,在任意服务器间都是唯一的。对于目前分布式系统来说,这简直就是噩梦。
  • 交互多:业务还需要额外执行一次类似 last_insert_id() 的函数才能知道刚才插入的自增值,这需要多一次的网络交互。在海量并发的系统中,多1条SQL,就多一次性能上的开销。
  • 性能差:自增ID的性能较差,需要在数据库服务器端生成。对于高并发的负载,innodb在按主键进行插入的时候会造成明显的锁争用,主键的上界会成为争抢的热点,因为所有的插入都发生在这里,并发插入会导致间隙锁竞争。
  • 分布式架构,多个Mysql实例可能会导致ID重复。
  • 容易被外界攻破,知道业务实际情况。且例如:显示公告内容index?id=3这样就很容易被人篡改为index?id=2.就可以调到第二条的内容。
  • 对于高并发的负载,innodb在按主键进行插入的时候会造成明显的锁争用,主键的上界会成为争抢的热点,因为所有的插入都发生在这里,并发插入会导致间隙锁竞争。Auto_Increment锁机制会造成自增锁的抢夺,有一定的性能损失。
  • 不利于数据迁移与扩展。

不适合自增ID为主键的情况:

  1. 数据量多需要分库分表,可能会造成ID重复
  2. 经常会遇到数据迁移的情况
  3. 新数据需要和老数据进行合并,导入旧数据时,可能会ID重复。

22、什么是uuid

        UUID是Universally Unique Identifier的缩写,即通用唯一标识符。它是通过MAC地址,时间戳,命名空间,随机数,伪随机数来保证生成ID的唯一性,有着固定的大小(128bit)。它的唯一性和一致性特点使得可以无需注册过程就能够产生一个新的UUID。UUID可以被用作多种用途,既可以用来短时间内标记一个对象,也可以可靠的辨别网络中的持久性对象。

MySQL中的UUID组成 = [时间低位+时间中位+时间高位](16字节)- 时钟序列(4字节) - MAC地址(12字节)

image-20220928231045391

  优点:

  • 保证了全局唯一性
  • 更加安全

缺点:

  • 存在隐私安全的问题,因为UUID包含了MAC地址,也就是机械的物理地址。
  • 无序,随机生成与插入,聚集索引频繁页分裂,大量随机IO,内存碎片化,特别是随着数据量越来越多,插入性能会越差。
  • 占用36字节,比较浪费空间

23、有序uuid作为主键

  • mysql自带的函数uuid()既可生成uuid。
  • mysql8.0版本提供了uuid_to_bin(uuid_string, [flag] )函数可以把uuid字符串变(去掉连接符-)成二进制,如果给定第二参数1或true,就会交互时间高位和时间地位的位置这样就由无序变成了有序!
  • hex()函数能把二进制转换成十六进制, unhex() 把十六进制转换成二进制。
  • 保存二进制使用binary(16)类型
CREATE TABLE `jinjiang`.`test_table`(  
  `uuid` BINARY(16) NOT NULL,
  `uuid_string` VARCHAR(64),
  `num` INT(4),
  PRIMARY KEY (`uuid`)
) ENGINE=INNODB;

-- 定义一个变量
SET @uuid_string = UUID();
-- 交换时间高位、时间地位的顺序
INSERT INTO test_table(`uuid`, uuid_string, num) VALUE(uuid_to_bin(@uuid_string, 1), @uuid_string, 1);
-- 不交换
INSERT INTO test_table(`uuid`, uuid_string, num) VALUE(uuid_to_bin(@uuid_string), @uuid_string, 2);
-- 查询
SELECT `uuid`, HEX(`uuid`), uuid_string, num FROM test_table ORDER BY num;

执行结果如图:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值