MySQL面试追魂夺命12问,你顶的住吗?

220 阅读14分钟

写在前面

如果对你有帮助,给博主一个免费的点赞以示鼓励把QAQ

欢迎各位~点赞 ~评论 ~ 收藏 ~ 🎄冲冲冲🎄

————————————————

1、MySQL中有哪些存储引擎?

Mysql体系架构如下图: 从体系结构图中可以发现,MySQL数据库区别于其他数据库的最重要的一个特点就是其插件式的表存储引擎。 插件式存储引擎的好处是,每个存储引擎都有各⾃的特点,能够根据具体的应用建立不同存储引 擎表。

image.png

InnoDB存储引擎

InnoDB是MySQL的默认事务型引擎,也是最重要、使用最广泛的存储引擎。它被设计用来处理大量的短期(short-lived)事务,应该优先考虑InnoDB引擎。

MylSAM存储引擎

在MySQL 5.1及之前的版本,MyISAM是默认的存储引擎。 但是MyISAM不支持事务和行级锁,而且崩溃后无法安全恢复。 同时MyISAM对整张表加锁,很容易因为表锁的问题导致典型的的性能问题。

Memory 引擎

Memory表至少比MyISAM 表要快一个数量级,数据⽂件是存储在内存中。Memory表的结构在重启以后还会保留,但数据会丢失。

Memroy表在很多场景可以发挥好的作用:

用于查找(lookup)或者映射(mapping)表,例如将邮编和州名映射的表。 用于缓存周期性聚合数据(periodically aggregated data)的结果。 用于保存数据分析中产⽣的中间数据。

Archive引擎

Archive存储引擎只⽀持INSERT和SELECT操作,会缓存所有的写并利用zlib对插入的行进行压缩,所以比MyISAM表的磁盘I/O更少。但是每次SELECT查询都需要执⾏全表扫描。所以Archive表适合日志和数据采集类应用。

CSV引擎

CSV引擎可以将普通的CSV文件(逗号分割值的⽂件)作为MySQL 的表来处理,但这种表不支持索引。因此CSV引擎可以作为一种数据交换的机制,非常有用

2、MyISAM和InnoDB的区别是什么?

1.InnoDB 支持事务,MyISAM 不支持事务。

这是 MySQL 将默认存储引擎从 MyISAM 变成 InnoDB 的重要原因之一;

2.InnoDB 支持外键,而 MyISAM 不支持。

对一个包含外键的 InnoDB 表转为 MYISAM 会失败;

3.InnoDB 是聚集索引,MyISAM 是非聚集索引。

聚簇索引的⽂件存放在主键索引的叶子节点上,因此 InnoDB 必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因 为主键太大,其他索引也都会很大。 而MyISAM 是非聚集索引,数据⽂件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的

4.InnoDB 不保存表的具体行数,执行 select count(*) from table 时需要全表扫描。而MyISAM用一个变量保存了整个表的⾏数,执⾏上述语句时只需要读出该变量即可,速度很快;

5.InnoDB 最小的锁粒度是行锁,MyISAM 最小的锁粒度是表锁。

一个更新语句会锁住整张表,导致其他查询和更新都会被阻塞,因此并发访问受限。这也是 MySQL 将默认存储引擎从 MyISAM 变成 InnoDB 的重要原因之一;

3、数据库表设计时,字段你会如何选择?

  1. 字段类型优先级 整型 > date,time > enum char > varchar > blob,text 选用字段长度最小、优先使用定长型、数值型字段中避免使用 “ZEROFILL” time : 定长运算快,节省时间,考虑时区,写sql不方便 enum : 能约束值的目的,内部用整形来储存,但与char联查时,内部要经历串与值的转化 char : 定长,考虑字符集和校对集 varchar : 不定长,要考虑字符集的转换与排序时的校对集,速度慢
    text,blob : 无法使用内存临时表(排序操作只能在磁盘上进行) 注意:date,time的选择可以直接选择使用时间戳,enum("男","女") //内部转成数字来储存,多了一个转换的过程,可以使用tinyint代替最好使用tinyint。

  2. 可以选整型就不选字符串 整型是定长的,没有国家/地区之分,没有字符集差异。例如:tinyint 和 char(1) 从空间上看都是一字节,但是 order by 排序 tinyint 快。原因是后者需要考虑字符集与校对集(就是排序优先集)。

  3. 够用就行不要慷慨 大的字段影响内存影响速度。以年龄为例:tinyint unsigned not null;可以储存255岁,足够了,⽤int浪费 3个字节。以varchar(10),varchar(300)储存的内容相同,但在表中查询时,varhcar(300)要花用更多内 存。

  4. 尽量避免使用NULL Null不利于索引,也不利于查询。=null或者!= null都查询不到值,只有使用is null或者is not null才可 以。因此可以在创建字段时候使用 not null default "" 的形式。

  5. char与varchar选择 char⻓度固定,处理速度要⽐varchar快很多,但是相对较费存储空间;所以对存储空间要求不大,但在 速度上有要求的可以使用char类型,反之可以用

4、Mysql中VARCHAR(M)最多能存储多少数据?

对于VARCHAR(M)类型的列最多可以定义65535个字节。其中的M代表该类型最多存储的字符数量,但在实际存储时并不能放这么多。

MySQL对一条记录占用的最大存储空间是有限制的,除了BLOB或者TEXT类型的列之外,其他所有的 列(不包括隐藏列和记录头信息)占用的字节长度加起来不能超过65535个字节。

5、请说下事务的基本特性

事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。 原子性指的是一个事务中的操作要么全部成功,要么全部失败。

一致性指的是数据库总是从一个一致性的状态转换到另外一个一致性的状态。 比如A转账给B100块钱, 假设中间sql执行过程中系统崩溃A也不会损失100块,因为事务没有提交,修改也就不会保存到数据库。

隔离性指的是一个事务的修改在最终提交前,对其他事务是不可见的。

持久性指的是一旦事务提交,所做的修改就会永久保存到数据库中。

6、事务并发可能引发什么问题?

脏读

1、在事务A执⾏过程中,事务A对数据资源进行了修改,事务B读取了事务A修改后的数据。 2、由于某些原因,事务A并没有完成提交,发生了RollBack操作,则事务B读取的数据就是脏数据。 这种读取到另一个事务未提交的数据的现象就是脏读(Dirty Read)。

image.png

不可重复读

事务B读取了两次数据资源,在这两次读取的过程中事务A修改了数据,导致事务B在这两次读取出来的 数据不一致。 这种在同一个事务中,前后两次读取的数据不⼀致的现象就是不可重复读(Nonrepeatable Read)

image.png

幻读

事务B前后两次读取同⼀个范围的数据,在事务B两次读取的过程中事务A新增了数据,导致事务B后⼀次读取到前一次查询没有看到的行。 幻读和不可重复读有些类似,但是幻读强调的是集合的增减,而不是单条数据的更新

image.png

7、简单描述下MySQL各种索引?

MySQL索引按字段特性分类可分为:主键索引、普通索引、前缀索引

  1. 主键索引 建立在主键上的索引被称为主键索引,一张数据表只能有一个主键索引,索引列值不允许有空值,通常 在创建表时一起创建。

image.png

  1. 唯一索引 建立在UNIQUE字段上的索引被称为唯一索引,一张表可以有多个唯一索引,索引列值允许为空,列值中出现多个空值不会发生重复冲突。

image.png

image.png

  1. 普通索引 建立在普通字段上的索引被称为普通索引。

image.png 4. 前缀索引 前缀索引是指对字符类型字段的前一个字符或对⼆进制类型字段的前几个bytes建⽴的索引,而不是在 整个字段上建索引。前缀索引可以建立在类型为char、varchar、binary、varbinary的列上,可以大大减少索引占用的存储空间,也能提升索引的查询效率。

前缀索引是一种能使索引更⼩更快的有效方法,但是也包含缺点:mysql无法使⽤前缀索引做order by 和 group by

image.png

image.png

8、什么是三星索引?

对于一个查询而言,一个三星索引,可能是其最好的索引。 如果查询使用三星索引,一次查询通常只需要进行一次磁盘随机读以及⼀次窄索引片的扫描,因此其相 应时间通常比使用一个普通索引的响应时间少几个数量级。

一个查询相关的索引行是相邻的或者至少相距足够靠近的则获得一星; 如果索引中的数据顺序和查找中的排列顺序⼀致则获得二星; 如果索引中的列包含了查询中需要的全部列则获得三星。

三星索引在实际的业务中如果⽆法同时达到,一般我们认为第三颗星最重要,第一和第二颗星重要性差不多,根据业务情况调整这两颗星的优先度

8、InnoDB一棵B+树可以存放多少行数据?

这个问题的其实非常简单:约2千万 计算机在存储数据的时候,有最小存储单元,在计算机中磁盘存储数据最小单元是扇区(这就好比我们今 天进行现金的流通最小单位是一毛),一个扇区的大小是 512 字节,而文件系统(例如XFS/EXT4)的最小单元是块,一个块的大小是 4k,而对于我们的 InnoDB 存储引擎也有自己的最小储存单元——页 (Page),一个页的大小是 16K。

image.png

Innodb 的所有数据文件(后缀为 ibd 的文件),他的大小始终都是 16384(16k)的整数倍。

image.png

数据表中的数据都是存储在页中的,所以一个页中能存储多少⾏数据呢?假设一行数据的大小是 1k,那 么一个页可以存放 16 行这样的数据。

对于B+树而言,只有叶子节点存放数据,非叶子节点存放的是只保存索引信息和下一层节点的指针信 息。一个非叶子节点能存放多少指针?

其实这也很好算,我们假设主键 ID 为常用的bigint 类型,长度为 8 字节,而指针大小在 InnoDB 源码中 设置为 6 字节,这样一共 14 字节,我们一个页中能存放多少这样的单元,其实就代表有多少指针,即 16384/14=1170个。

那么可以算出⼀棵⾼度为2的B+树,存在一个根节点和若干个叶子节点能存放 1170*16=18720 条这样的数据记录。

根据同样的原理我们可以算出一个高度为 3 的B+ 树可以存放: 1170117016=21902400 条这样的记录

10、如何提高insert的性能?

1、合并多条 insert 为一条 即: insert into t values(a,b,c), (d,e,f) ,,, 原因分析:主要原因是多条insert合并后日志量(MySQL的binlog和innodb的事务日志)减少了,降低日志刷盘的数据量和频率,从而提高效率。通过合并SQL语句,同时也能减少SQL语句解析的次数,减 少⽹络传输的IO。

2、修改参数 bulk_insert_buffer_size,调⼤批量插入的缓存;

3、设置 innodb_flush_log_at_trx_commit = 0 相对于 innodb_flush_log_at_trx_commit = 1 可以十分明显的提升导入速度; innodb_flush_log_at_trx_commit 参数解释如下:

0:log buffer中的数据将以每秒⼀次的频率写入到log file中,且同时会进行文件系统到磁盘的同步操 作,但是每个事务的commit并不会触发任何log buffer 到log file 的刷新或者文件系统到磁盘的刷新操作;

1:在每次事务提交的时候将log buffer 中的数据都会写⼊到log file,同时也会触发文件系统到磁盘的同步;

2:事务提交会触发log buffer 到log file的刷新,但并不会触发磁盘⽂件系统到磁盘的同步。此外,每秒 会有一次文件系统到磁盘同步操作。

4、手动使用事务 因为mysql默认是autocommit的,这样每插入一条数据,都会进行一次commit;所以,为了减少创建事务的消耗,我们可用手工使用事务 即START TRANSACTION;insert 。。,insert。。 commit;即执⾏多个insert后再一起提交;一般1000 条insert 提交一次。

11、什么是全局锁、共享锁、排它锁?

全局锁就是对整个数据库实例加锁

它的典型使用场景就是做全库逻辑备份。这个命令可以使整个库处于只读状态。使用该命令之后,数据更新语句、数据定义语句、更新类事务的提交语句等操作都会被阻。

共享锁又称读锁 (read lock),是读取操作创建的锁

其他⽤户可以并发读取数据,但任何事务都不能对数据进行修改(获取数据上的排他锁),直到已释放所有共享锁。当如果事务对读锁进⾏修改操作,很可能会造成死锁。

排他锁 exclusive lock(也叫 writer lock)又称写锁。

若某个事物对某一行加上了排他锁,只能这个事务对其进行读写,在此事务结束之前,其他事务不能对 其进行加任何锁,其他进程可以读取,不能进行写操作,需等待其释放。排它锁是悲观锁的一种实现。

若事务 1 对数据对象 A 加上 X 锁,事务 1 可以读 A 也可以修改 A,其他事务不能再对 A 加任何锁,直到事物 1 释放 A 上的锁。这保证了其他事务在事物 1 释放 A 上的锁之前不能再读取和修改 A。排它锁会阻塞所有的排它锁和共享锁

12、谈一下MySQL中的死锁

死锁是指两个或两个以上的进程在执⾏过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁。

如何查看死锁? 使用命令 show engine innodb status 查看最近的一次死锁。 InnoDB Lock Monitor 打开锁监控,每 15s 输出一次日志。使⽤完毕后建议关闭,否则会影响数据库性能。

对待死锁常⻅的两种策略: 通过 innodblockwait_timeout 来设置超时时间,一直等待直到超时;

发起死锁检测,发现死锁之后,主动回滚死锁中的某一个事务,让其它事务继续执行。

文章中出现的关于面试题的错误请在评论区指出,我再进行改正优化, 如果文章对你有所帮助,请给博主一个免费的三连吧,感谢大家