mysql面试

1. MySQL中myisam与innodb的区别

  1. InnoDB支持事物,而MyISAM不支持事物
  2. InnoDB支持行级锁,而MyISAM支持表级锁
  3. InnoDB支持MVCC, 而MyISAM不支持
  4. InnoDB不支持全文索引,而MyISAM支持。
  5. InnoDB表支持多种行格式, myisam 不支持
  6. InnoDB是索引组织表, myisam 是堆表(索引和数据分离的)
  7. InnoDB不能通过直接拷贝表文件的方法拷贝表到另外一台机器, myisam 支持
  8. InnoDB支持外键,而MyISAM不支持

2. MySQL中的行格式

MySQL 5.1时,InnoDB存储引擎提供了Compact和Redundant两种格式来存放行记录数据,Redundant是为兼容之前版本而保留的 。

Compact格式
在这里插入图片描述

下面用一个具体事例来分析Compact行记录的内部结构:
 
create table mytest (
 
  t1 varchar(10),
 
  t2 varchar(10),
 
  t3 char(10),
 
  t4 varchar(10)
 
) engine=innodb charset=latin1 row_format=compact;
 
insert into mytest values('a','bb','bb','ccc'); 
 
03 02 01/*变长字段长度列表,逆序*/ 第一个varchar 1byte 第二个2byte,第三个3byte
00/*NULL标志位,第一行没有NULL值*/ 转为2进制是0000 0000,因为只有4个字段,只有后面0000起作用
00 00 10 00 2c/*记录头信息,固定5字节长度*/
00 00 00 2b 68 00/*RowID我们建的表没有主键,因此会有RowID*/
00 00 00 00 06 05/*TransactionID*/
80 00 00 00 32 01 10/*Roll Pointer*/
61/*列1数据'a' 长度01  */
62 62/*列2'bb' 长度02*/
62 62 20 20 20 20 20 20 20 20/*列3数据'bb'*/
63 63 63/*列4数据'ccc' 长度03*/
 
 
insert into mytest values('d',NULL,NULL,'fff'); 
 
03 01/*变长字段长度列表,逆序*/第一个varchar(‘d’)1byte  第二个('fff')3byte
 
06/*NULL标志位,第三行有NULL值*/转为2进制是0000 0110,只有后面0110起作用,表示第二,三为NULL
 
00 00 20 ff 98/*记录头信息*/
 
00 00 00 2b 68 02/*RowID*/
 
00 00 00 00 06 07/*TransactionID*/
 
80 00 00 00 32 01 10/*Roll Pointer*/
 
64/*列1数据'd'*/
 
66 66 66/*列4数据'fff'*/

3. MySQL中varchar与char的区别

  • char(N)如果存储的字节数超过 N,那么 char( N)将和 varchar( N)没有区别。
  • 如果存储的字节数少于 N,那么存储 N 个字节,后面补空格,补到 N 字节长度。
  1. 对于InnoDB表,因为它的数据行内部存储格式对固定长度的数据行和可变长度的数据行不加区分(所有数据行共用一个表头部分,这个标头部分存放着指向各有关数据列的指针),所以使用char类型不见得会比使用varchar类型好。事实上,因为char类型通常要比varchar类型占用更多的空间,所以从减少空间占用量和减少磁盘i/o的角度,使用varchar类型反而更有利;
  2. 存储很短的信息,比如门牌号码101,201……这样很短的信息应该用char,因为varchar还要占个byte用于存储信息长度,本来打算节约存储的现在得不偿失。
  3. 固定长度的。比如使用uuid作为主键,那用char应该更合适。因为他固定长度,varchar动态根据长度的特性就消失了,而且还要占个长度信息。
  4. 十分频繁改变的column。因为varchar每次存储都要有额外的计算,得到长度等工作,如果一个非常频繁改变的,那就要有很多的精力用于计算,而这些对于char来说是不需要的。

4. varchar(50)中50的涵义

  • 最多存放50个字符,varchar(50)和(200)存储hello所占空间一样,但后者在排序时会消耗更多内存,因为order by col采用fixed_length计算col长度。
  • Compact格式变长字段长度列表,当列的长度小于255字节,用1字节表示,若大于255个字节,用2个字节表示,变长字段的长度最大不可以超过2个字节。即理想情况中varchar的最大长度为65535(不算上一些头信息的且此行只声明了一个varchar)。InnoDB存储引擎的页为16KB,即16 384个字节,怎么能存放65535个字节呢(行溢出)?一般情况下,数据都是存放在B-tree Node的页类型中,但是当发生行溢处时,则这个存放行溢处的页类型为Uncompress BLOB Page.因此,如果varchar太长的话,DBA会要求直接定义BLOB格式(会使用Compressed与Dynamic行记录格式)。

5. int(20)中20的涵义

是指显示字符的长度,不影响内部存储。

6.mysql 的索引有哪几种

  1. B+tree索引
  2. hash索引

7.mysql B+树索引的分裂优化

针对1,2,3,4,5,6,7,8,9的记录,如果插入10 将拆分成page1[1,2,3,4] , page2[5,6,7,8,9,10],由于是顺序(逆序)插入,page1将造成极大的浪费,

  1. 若插入是随机的,则取页的中间记录作为分裂点的记录,这和之前介绍的相同。
  2. 若往同一方向进行插入的记录数量为5,并且目前已经定位( cursor)到的记录( InnoDB存储引擎插入时,首先需要进行定位,定位到的记录为待插人记录的前条记录)之后还有3条记录,则分裂点的记录为定位到的记录后的第三条记录
  3. 否则分裂点记录就是待插入的记录。

8. mysql B+树索引的名词解释

  1. 聚集索引
    按照每张表的主键构造一颗B+树,并且叶节点存放着整张表的行记录数据

  2. 辅助索引
    也称非聚集索引,叶节点不包含行的全部数据,只是存着(Key+主键)。

  3. 联合索引
    mysql面试_第1张图片
    运用的是多个索引列(对第一排序,再对第二列排序)。 创建方法跟单个索引一样。

  4. 覆盖索引
    就是从辅助索引中查询的记录,而不需要查询聚集索引中的记录。 好处就是辅助索引不包含整个行记录的所有信息,页面大小远小于聚集索引。因此可以减少大量的IO操作。

例设表t,(OrderID,ProductID)的联合索引
现在对表查询 select OrderID,ProductID from t
直接在我们的(OrderID,ProductID)的联合索引中可以拿的到,不用去聚集索引再拿。这种情况称为覆盖索引。

9. sql优化

  1. explain分析
    一般来说,要看到尽量用 index(type 为 const、 ref 等, key 列有值),避免使用全表扫描(type 显式为 ALL)
  2. 字段是否可加索引分析
    对于性别,可取值的范围只有’M’、‘F’。对上述SQL语句得到的结果可能是该表50%的数据(我们假设男女比例1:1),这时添加B+树索引是完全没有必要的。相反,如果某个字段的取值范围很广,几乎没有重复,即高选择性,则此时使用B+树索引是最适合的,例如姓名字段,基本上在一个应用中都不允许重名的出现。 通过SHOW INDEX结果中的列Cardinality来观察,Cardinality值非常关键,优化器会根据这个值来判断是否使用这个索引。但是这个值并不是实时更新的。可以使用ANALYZE TABLE命令强制更新。
  3. profile分析
    用来分析 sql 性能的消耗分布情况。当用 explain 无法解决慢 SQL 的时候,需要用profile 来对 sql 进行更细致的分析,找出 sql 所花的时间大部分消耗在哪个部分,确认 sql的性能瓶颈。

10. mysql中事务的4大特性

  1. 原子性
  2. 一致性
  3. 隔离性
  4. 持久性

11. mysql的隔离级别

  1. 未提交读
  2. 提交读
  3. 可重复读
  4. 可串行化

12. mysql的锁类型

  • 共享锁(S LOCK) : 允许事务读一行(表)数据
  • 排它锁(X LOCK) : 允许事务删除或更新一(表)数据
  • 意向共享锁(IS Lock) : 事务想要获得一张表中某几行的共享锁
  • 意向共享锁(IX Lock) : 事务想要获得一张表中某几行的排它锁

需要用的锁的时候自动加载,例 select for update, update ,delete;
当运行delete t where id =1;的时候,获取了 t 表的 IX, 获取了记录的 X;

12. mysql的锁算法

  • Record Lock : 单个行记录上的锁
  • Gap Lock : 间隙锁,锁定一个范围,单不包含记录本身
  • Next-Key Lock : Gap Lock + Record Lock,锁定一个范围,并且锁定记录本身

针对表z,a为聚集索引,b是普通索引
create table z( a INT, b INT, PRIMARY KEY(a), KEY(b));
INSERT INTO z SELECT 1,1;
INSERT INTO z SELECT 3,1;
INSERT INTO z SELECT 5,3;
INSERT INTO z SELECT 7,6;
INSERT INTO z SELECT 10,8;
当运行select * from z where b = 3 for update;
聚集索引上id为5的会被上Record Lock,普通索引(1,3)和(3,6)被加上Gap Lock

13. mysql mvcc原理

Undo log:回滚而记录的这些东西称之为撤销日志。

  1. 假设有记录
    mysql面试_第2张图片
  2. 事务01进来,获取记录锁,对记录修改,释放锁
    mysql面试_第3张图片
  3. 事务02进来,获取记录锁,对记录修改,释放锁
    mysql面试_第4张图片
  4. 如果现在事务1.5中,执行select查询记录
  • RR级别下,事务中的第一个SELECT请求才开始创建read view;
    1. try_id < up_try_id , 数据在事务开始前已经提交改可见
    2. up_try_id <= try_id <= low_try_id ,数据在事务开启前末提交,不可见
    3. try_id>low_try_id, 数据在事务启动后被提交,不可见(后面的事务提交速度超过当前事务)

事务1.5开始的时候,事务列表为(1,1.5)。即计算得列表中最早末提交的事务 up_try_id = 1, 最晚提交事务low_try_id = 1.5
第一条记录事物try_id=null < low_try_id =1,可见
第二条记录事物 low_try_id =1 <= try_id= 1 < up_try_id = 1.5,不可见,因为还没提交.
第三条记录事物try_id= 2 > up_try_id = 1.5,不可见,当前事务之后被修改

14. 事务及恢复实现原理

  • Undo log:回滚而记录的,称之为撤销日志。它和数据页是同等级的。如果undo log被改一半死机,数据页也随着消失,如果数据页持久化undo也被执久。
  • redo :记录页修改的时的日志(就是页数据执久化的部分)。页修改的时候,它会先写到 buffer 里面, 等到达一点条件同步到磁盘文件( fsync)。因为当事务提交的时候redo会同步到磁盘,所以提交后死机,也可以快速恢复。

log buffer根据一定的规则将log block刷新到磁盘:

  1. 事务提交时
  2. 当log buffer中一半的空间已经被使用
  3. log checkpoint时 (page页被刷新到磁盘的时候)

InnoDB的redo log是固定大小的,比如可以配置为一组4个文件,每个文件的大小是1GB,那么这块“粉板”总共就可以记录4GB的操作。从头开始写,写到末尾就又回到开头循环写,如下面这个图所示。
mysql面试_第5张图片
write pos是当前记录的位置,一边写一边后移,写到第3号文件末尾后就回到0号文件开头。当page页被刷新到磁盘的时候,redo log 会记录checkpoint,这样checkpoint之前的数据就可以擦除。当发生死机需要恢复时,只要拿磁盘上page数据+checkpoint到write_post的数据

15. binlog的几种格式

  • ROW(行模式):记录那条数据修改了,注意:记录的是这条记录的全部数据,即使只更新了一个字段,binlog里也会记录所有字段的数据

    • 优点:他不记录sql语句的上下文信息,日志内容会非常清楚的记录每条数据详细的变更细节,即使只更新了一个字段,binlog里也会记录所有字段的数据。
    • 缺点:binlog日志会非常大,mysql主从同步时,会产生大量磁盘IO
  • Statement(语句模式): 每一条会修改数据的sql都会记录在binlog中。

    • 优点:不需要记录每一行的变化,减少了binlog日志量,节约了IO,提高性能。
    • 缺点:由于记录的只是执行语句,为了这些语句能在slave上正确运行,因此还必须记录每条语句在执行的时候的一些相关信息,以保证所有语句能在slave得到和在master端执行时候相同 的结果。另外mysql 的复制,像一些特定函数功能,slave可与master上要保持一致会有很多相关问题。
  • Mixed(混合模式):在Mixed模式下,一般的语句修改使用statment格式保存binlog,如一些函数,statement无法完成主从复制的操作,则采用row格式保存binlog,MySQL会根据执行的每一条具体的sql语句来区分对待记录的日志形式,也就是在Statement和Row之间选择一种。

16. 2pc之redo与binlog

  • redo log是InnoDB引擎特有的; binlog是MySQL的Server层实现的,所有引擎都可以使用。
  • redo log是物理日志,记录的是“在某个数据页上做了什么修改”; binlog是逻辑日志,记录的是这个语句的原始逻辑,比如“给ID=2这一行的c字段加1 ”。

因为他们之间都是事务的保证,当事务成功这2都必须全部成功。 会存在一个内部XA的问题:事务在存储引擎层(redo)commit的顺序和在binlog中提交的顺序不一致的问题。2pc流程如下

mysql面试_第6张图片
第一阶段:InnoDB prepare,持有prepare_commit_mutex,并写入到redo log中。将回滚段(undo)设置为Prepared状态,binlog不做任何操作。

mysql面试_第7张图片
第二阶段:将事务写入Binlog中,将redo log中的对应事务打上commit标记,并释放prepare_commit_mutex。
MySQL以binlog的写入与否作为事务是否成功的标记,innodb引擎的redo commit标记并不是这个事务成功与否的标记。

崩溃时:
​ 1. 扫描最后一个Binlog文件,提取其中所有的xid。
​ 2. InnoDB维持了状态为Prepare的事务链表,将这些事务的xid与刚刚提取的xid做比较,若存在,则提交prepare的事务,若不存在,回滚。

你可能感兴趣的:(#,面试整理)