MySQL面试知识点汇总

文章目录

    • 1、三范式
    • 2、基本命令
    • 3、存储引擎
    • 4、索引
    • 5、事务
    • 6、ACID
    • 7、隔离级别
    • 8、MVCC
    • 9、日志
    • 10、主从复制
    • 11、锁
    • 12、drop、delete 、truncate

1、三范式

专注于消除冗余即可

  • 第一范式

    要求一行中的每个单元格都应该有单一值,且不能出现重复列

  • 第二范式

    要求每张表都应该有一个单一目的,即它只能代表一种且仅有一种实体类型。

    一张表中的每一列都描述该表代表的实体。

  • 第三范式表中的列不应派生自其他列

2、基本命令

3、存储引擎

InnoDB:MySQL 默认的事务型存储引擎;

MyISAM

对比:

InnoDB MyISAM
行级锁 ×
事务 ×
外键 ×
数据库异常崩溃后的安全恢复 ×
MVCC ×

4、索引

索引是一种高效获取数据的数据结构。

优势 劣势
提高数据检索的效率,降低数据库的IO成本 索引列也是要占用空间的
通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗 索引大大提高了查询效率,同时却也降低更新表的速度,如对表进行INSERT、UPDATE、DELETE时,效率降低

索引结构

索引是在存储引擎层实现的,不同的存储引擎有不同的结构

  • B+树索引
  • hash索引,用哈希表实现,只支持精确匹配,不支持范围查询

相比于B树,B+树所有节点都会出现在叶子结点,叶子结点形成一个链表,非叶子结点起到索引作用,叶子结点存储数据。MySQL索引数据结构对经典的B+树进行了优化。在原B+树的基础上,增加一个指向相邻叶子节点的链表指针,就形成了带有顺序指针的B+树,提高区间访问的性能。

哈希索引就是采用一定的hash算法,将键值换算成新的hash值,映射到对应的槽位上,然后存储在hash表中。

Hash索引只能用于对等比较(=,in),不支持范围查询;

无法利用索引完成排序操作;

查询效率高,通常只需要一次检索就可以了,效率通常要高于B+tree索引。

为什么InnoDB存储引擎选择使用B+tree索引结构?

相对于二叉树,层级更少,搜索效率高;
对于B-tree,无论是叶子节点还是非叶子节点,都会保存数据,这样导致一页中存储的键值减少,指针跟着减少,要同样保存大量数据,只能增加树的高度,导致性能降低;
相对Hash索引,B+tree支持范围匹配及排序操作。

索引分类:

主键索引:只能有一个

唯一索引

常规索引

全文索引

在InnoDB存储引擎中,也可以分为以下两类:

  • 聚集索引:将数据存储与索引放到了一块,索引结构的叶子节点保存了行数据。有且只有一个。

    叶子结点下挂的是这一行的行数据。

    聚集索引选取规则:

    • 如果存在主键,主键索引就是聚集索引。
    • 如果不存在主键,将使用第一个唯一(UNIQUE)索引作为聚集索引。
    • 如果表没有主键,或没有合适的唯一索引,则nnoDB会自动生成一个rowid作为隐藏的聚集索引。
  • 二级索引:将数据与索引分开存储,索引结构的叶子节点关联的是对应的主键。可以存在多个。

    叶子结点下挂的是这一行的id。

回表查询:先到二级索引找到对应的主键值,在到聚集索引中拿到这一行的行数据。

索引语法

MySQL面试知识点汇总_第1张图片

5、事务

事务是代表单个工作单元的一组SQL语句,所有这些语句都必须成功完成,否则事务会运行失败。

6、ACID

  • 原子性
  • 一致性——通过使用事务,数据库将始终保持一致的状态
  • 隔离性——事务相互隔离,不会互相干扰,一个只有一个事务可以更新数据库
  • 持久性——一旦被提交,事务的更改是永久的

7、隔离级别

常见的并发问题——

  • 丢失更新:当两个事务尝试更新相同的数据并且没有上锁时,较晚提交的事务会覆盖先提交的事务。

    解决方法:使用锁

  • 脏读:一个事务读取了未提交的数据

    解决方法:建立事务隔离级别——读已提交

  • 不可重复读:读取多次数据,结果不一样(中途被修改了)

    解决方法:建立事务隔离级别——可重复读

  • 幻读:无法在查询中看到,在查询后才添加、修改、删除的数据

    解决方法:建立事务隔离级别——可串行化,如果发生了别的事影响查询结果,当前事务必须等它们完成。

事务隔离级别——

读未提交:最低等,可能会遇到所有并发问题

读已提交 : 解决脏读

可重复读(默认):解决丢失更新、脏读、不可重复读

可串行化:解决丢失更新、脏读、不可重复读、幻读

隔离级别越高,越影响性能和可扩展性。

InnoDB 存储引擎默认使用 REPEATABLE-READ(可重读)

InnoDB 存储引擎在 分布式事务 的情况下一般会用到 SERIALIZABLE(可串行化) 隔离级别。

事务隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted)
不可重复读(read-committed)
可重复读(repeatable-read)
串行化(serializable)

8、MVCC

基本概念——

  • 当前读:读取的是记录的最新版本,读取时保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。
  • 快照读:简单的select数据,有可能是历史数据,不加锁,非阻塞

MVCC,全称 Multi-Version Concurrency Control ,即多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,快照读为MySQL实现MVCC提供了一个非阻塞读功能。MVCC的具体实现,依赖于数据库记录中的三个隐式字段、undo log日志、readView。

MVCC实现原理

  1. 记录中的隐式字段

    DB_TRX_ID:最近修改事务ID

    DB_ROLL_PTR:回滚指针,指向这条记录的上一个版本,用于配合undo log,指向上一个版本

    DB_ROW_ID:隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段

  2. undo log日志

    回滚日志,在insert、update、delete的时候产生的便于数据回滚的日志;

    在insert的时候,产生的undo log日志只在回滚时需要,在事务提交之后,可立即被删除;

    在update、delete的时候,产生的undo log日志不仅在回滚时需要,也在快照读时需要,不会被立即删除。

    undo log版本链

    不同的事务或者同一事务对同一条记录进行修改,会导致该记录的undo log生成一条记录版本链表,链表的头部是最新的旧记录,尾部是最早的旧记录。

    MySQL面试知识点汇总_第2张图片

  3. readView

    readView(读视图)是快照读SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id,决定了快照读的时候读取哪一个历史记录。

    readView包含四个核心字段:

    • m_ids:当前活跃的事务id集合
    • min_trx_id:最小活跃事务id
    • max_trx_id:预分配事务id,当前最大事务id + 1
    • creator_trx_id:readView创建者的事务id

    在可重复读隔离级别下,仅在事务第一次执行快照读的时候生成readView,后续复用该readView,保证了读取到相同的记录。

9、日志

(1)错误日志

错误日志记录了MySQL启动和停止时,以及服务器在运行过程中发生任何严重错误时的相关信息。当数据库出现任何故障导致无法正常使用时,建议首先查看错误日志。

(2)二进制日志

二进制日志(BINLOG)记录了所有的DDL(数据定义语言)和DML(数据操纵语言)语句,但不包括数据查询(SELECT、SHOW)语句。

作用:

  • 灾难时的数据恢复
  • MySQL的主从复制

日志格式:

  • STATEMENT:基于SQL语句的日志记录,记录的是SQL语句,对数据进行修改的SQL语句都会记录在日志文件中;
  • ROW:基于行的日志记录,记录的是每一行的数据变更(默认);
  • MIXED:混合了STATEMENT和ROW两种日志格式,默认采用STATEMENT,在某些情况下会切换成ROW。

(3)查询日志

记录了客户端中所有的操作语句,默认情况下不开启。

(4)慢查询日志

记录了执行效率低、速度慢的SQL语句,默认情况下不开启。

long_query_time默认10秒,最小为0。

10、主从复制

什么是主从复制?有什么作用?

主从复制是指将主数据库的DDL和DML操作通过二进制日志传到从数据库中,然后在从数据库上对这些日志重新执行,从而使得从库和主库的数据保持同步。

作用:

  • 主库出现问题,可以快速切换从数据库提供服务;
  • 实现读写分离,降低主库的访问压力,增删改操作主库,查询操作从库;
  • 可以在从库中执行备份,避免备份期间影响主库服务。

原理

基于二进制日志

MySQL面试知识点汇总_第3张图片

11、锁

MySQL中的锁,按照锁的粒度分,分为以下三类:

  1. 全局锁:锁定数据库中的所有表。

    全局锁就是对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的DML的写语句,DDL语句,已经更新操作的事务提交语句都将被阻塞。其典型的使用场景是做全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性。

    怎么加全局锁?

    加锁:

    flush tables with read lock

    释放锁:

    unlock tables

  2. 表级锁:每次操作锁住整张表。

    锁的粒度大,发生锁冲突的概率高,并发度最低

    分类:

    • 表锁

      • 表共享读锁:不会阻塞其他客户端的读,会阻塞其他客户端的写
      • 表独占写锁:加了写锁,会阻塞其他客户端的读和写

      加锁:lock tables 表名… read/write

      解锁:unlock tables / 客户端断开连接

    • 元数据锁 meta data lock,MDL

      MDL加锁过程是系统自动控制,无需显式使用,在访问一张表的时候会自动加上。MDL的主要作用是维护表元数据的一致性,在表上有活动事务的时候,不可以对元数据进行写入操作。

      为了避免DDL和DML冲突,保证读写正确性。

      MDL读锁:共享锁,增删改查时

      MDL写锁:排他锁,对表结构进行变更操作时

    • 意向锁
      为了避免DML在执行时,加的行锁与表锁冲突,InnoDB引入了意向锁,使得表锁不用检查每一行是否加锁,使用意向锁来减少表锁的检查。

      • 意向共享锁(IS):由语句select…lock in share mode添加

        与表锁共享锁兼容,与表锁排他锁互斥

      • 意向排他锁(IX):增删改,select…for update

        与表锁共享锁、表锁排他锁都互斥,意向锁之间不会互斥

  3. 行级锁:每次操作锁住对应的行数据。

    每次操作锁住对应的行数据。锁的粒度最小,发生锁冲突的概率最低,并发度最高。

    InnoDB的数据是基于索引的,行锁是通过对索引上的索引项加锁来实现的,而不是对记录加的锁。对于行级锁,主要分为以下三类:

    **(1)行锁(Record Lock):**锁定单个行记录的锁,防止其他事务对此行进行update和delete。在RC、RR隔离级别下都支持。

    • 共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排它锁。
    • 排他锁(X):允许获取排他锁的事务更新数据,阻止其他事务获得相同数据集的共享锁和排他锁。

    共享锁和共享锁兼容,与排他锁互斥;

    排他锁和共享锁、排他锁都互斥;

    SQL 行锁类型 说明
    INSERT、UPDATE、DELETE 排他锁 自动加锁
    SELECT 不加任何锁
    SELECT…LOCK IN SHARE MODE 共享锁 手动在SELECT之后加LOCK IN SHARE MODE
    SELECT…LOCK FOR UPDATE 排他锁 手动在SELECT之后加LOCK FOR UPDATE

    InnoDB的行锁是针对于索引加的锁,如果不通过索引条件检索数据,那么InnoDB将对表中的所有记录加锁,此时就会升级为表锁。

    **(2)间隙锁(Gap Lock) :**锁定索引记录间隙(不含该记录),确保索引记录间隙不变,防止其他事务在这个间隙进行insert,产生幻读。在R隔离级别下都支持。

    **(3)临键锁(Next-Key Lock)︰行锁和间隙锁组合,同时锁住数据,并锁住数据前面的间隙Gap。**在RR隔离级别下支持。

    默认情况下,InnoDB在REPEATABLE READ事务隔离级别运行,InnoDB使用next-key锁进行搜索和索引扫描,以防止幻读。

    • 针对唯一索引进行检索时,对已存在的记录进行等值匹配时,将会自动优化为行锁。

    • 索引上的等值查询(唯一索引),给不存在的记录加锁时,优化为间隙锁。

    • 索引上的等值查询(普通索引),向右遍历时最后一个值不满足查询需求时,next-key lock退化为间隙锁。

    • 索引上的范围查询(唯一索引)–会访问到不满足条件的第一个值为止。

MySQL面试知识点汇总_第4张图片

MyISAM 和 InnoDB 存储引擎使用的锁:

  • MyISAM 采用表级锁(table-level locking)。
  • InnoDB 支持行级锁(row-level locking)和表级锁,默认为行级锁

12、drop、delete 、truncate

  • drop(丢弃数据): drop table 表名 ,直接将表都删除掉,在删除表的时候使用。
  • truncate (清空数据) : truncate table 表名 ,只删除表中的数据,再插入数据的时候自增长 id 又从 1 开始,在清空表中数据的时候使用。
  • delete(删除数据) : delete from 表名 where 列名 = 值,删除某一列的数据,如果不加 where 子句和truncate table 表名作用类似。

truncate 和 drop 属于 DDL(数据定义语言)语句,操作立即生效,原数据不放到 rollback segment 中,不能回滚,操作不触发 trigger

delete 语句是 DML (数据库操作语言)语句,这个操作会放到 rollback segement 中,事务提交之后才生效

你可能感兴趣的:(mysql)