转载BATJTMD-面试必问的-MySQL你懂了吗

37次阅读

共计 11709 个字符,预计需要花费 30 分钟才能阅读完成。

前言

明天不整那些花里胡哨、虚头巴脑的前言了,间接进入正题怼起来。

注释

二狗:不多 BB,先怼几道常问的大题目。MySQL 的事务隔离级别有哪些?别离用于解决什么问题?

次要用于解决脏读、不可反复读、幻读。

脏读:一个事务读取到另一个事务还未提交的数据。

不可反复读:在一个事务中屡次读取同一个数据时,后果呈现不统一。

幻读:在一个事务中应用雷同的 SQL 两次读取,第二次读取到了其余事务新插入的行。

不可反复读重视于数据的批改,而幻读重视于数据的插入。

隔离级别

脏读

不可反复读

幻读

读未提交(Read Uncommitted)

读已提交(Read Committed)

可反复读(Repeatable Read)

串行化(Serializable)

二狗:MySQL 的可反复读怎么实现的?

应用 MVCC 实现的,即 Mutil-Version Concurrency Control,多版本并发管制。对于 MVCC,比拟常见的说法如下,包含《高性能 MySQL》也是这么介绍的。

InnoDB 在每行记录前面保留两个暗藏的列,别离保留了数据行的 创立版本号 删除版本号。每开始一个新的事务,零碎版本号都会递增。事务开始时刻的版本号会作为事务的版本号,用来和查问到的每行记录的版本号比照。在可反复读级别下,MVCC 是如何操作的:

SELECT:必须同时满足以下两个条件,能力查问到。1)只查版本号早于以后版本的数据行;2)行的删除版本要么未定义,要么大于以后事务版本号。

INSERT:为插入的每一行保留以后零碎版本号作为创立版本号。

DELETE:为删除的每一行保留以后零碎版本号作为删除版本号。

UPDATE:插入一条新数据,保留以后零碎版本号作为创立版本号。同时保留以后零碎版本号作为原来的数据行删除版本号。

MVCC 只作用于 RC(Read Committed)和 RR(Repeatable Read)级别,因为 RU(Read Uncommitted)总是读取最新的数据版本,而不是合乎以后事务版本的数据行。而 Serializable 则会对所有读取的行都加锁。这两种级别都不须要 MVCC 的帮忙。

最后我也是深信这个说法的,然而前面发现在某些场景下这个说法其实有点问题。

举个简略的例子来说:如果线程 1 和线程 2 先后开启了事务,事务版本号为 1 和 2,如果在线程 2 开启事务的时候,线程 1 还未提交事务,则此时线程 2 的事务是不应该看到线程 1 的事务批改的内容的。

然而如果按下面的这种说法,因为线程 1 的事务版本早于线程 2 的事务版本,所以线程 2 的事务是能够看到线程 1 的事务批改内容的。

二狗:如同是有这个问题,那到底是怎么实现的?

实际上,InnoDB 会在每行记录前面减少三个暗藏字段:

DB_ROW_ID:行 ID,随着插入新行而枯燥递增,如果有主键,则不会蕴含该列。

DB_TRX_ID:记录插入或更新该行的事务的事务 ID。

DB_ROLL_PTR:回滚指针,指向 undo log 记录。每次对某条记录进行改变时,该列会存一个指针,能够通过这个指针找到该记录批改前的信息。当某条记录被屡次批改时,该行记录会存在多个版本,通过 DB_ROLL_PTR 链接造成一个相似版本链的概念。

接下来进入正题,以 RR 级别为例:每开启一个事务时,零碎会给该事务会调配一个事务 Id,在该事务执行第一个 select 语句的时候,会生成一个以后工夫点的事务快照 ReadView,次要蕴含以下几个属性:

  • trx_ids:生成 ReadView 时以后零碎中沉闷的事务 Id 列表,就是还未执行事务提交的。
  • up_limit_id:低水位,取 trx_ids 中最小的那个,trx_id 小于该值都能看到。
  • low_limit_id:高水位,生成 ReadView 时零碎将要调配给下一个事务的 id 值,trx_id 大于等于该值都不能看到。
  • creator_trx_id:生成该 ReadView 的事务的事务 Id。

有了这个 ReadView,这样在拜访某条记录时,只须要依照下边的步骤判断记录的某个版本是否可见:

1)如果被拜访版本的 trx_id 与 ReadView 中的 creator_trx_id 值雷同,意味着以后事务在拜访它本人批改过的记录,所以该版本能够被以后事务拜访。

2)如果被拜访版本的 trx_id 小于 ReadView 中的 up_limit_id 值,表明生成该版本的事务在以后事务生成 ReadView 前曾经提交,所以该版本能够被以后事务拜访。

3)如果被拜访版本的 trx_id 大于 ReadView 中的 low_limit_id 值,表明生成该版本的事务在以后事务生成 ReadView 后才开启,所以该版本不能够被以后事务拜访。

4)如果被拜访版本的 trx_id 属性值在 ReadView 的 up_limit_id 和 low_limit_id 之间,那就须要判断一下 trx_id 属性值是不是在 trx_ids 列表中。如果在,阐明创立 ReadView 时生成该版本的事务还是沉闷的,该版本不能够被拜访;如果不在,阐明创立 ReadView 时生成该版本的事务曾经被提交,该版本能够被拜访。

在进行判断时,首先会拿记录的最新版本来比拟,如果该版本无奈被以后事务看到,则通过记录的 DB_ROLL_PTR 找到上一个版本,从新进行比拟,直到找到一个能被以后事务看到的版本。

而对于删除,其实就是一种非凡的更新,InnoDB 用一个额定的标记位 delete_bit 标识是否删除。当咱们在进行判断时,会查看下 delete_bit 是否被标记,如果是,则跳过该版本,通过 DB_ROLL_PTR 拿到下一个版本进行判断。

以上内容是对于 RR 级别来说,而对于 RC 级别,其实整个过程简直一样,惟一不同的是生成 ReadView 的机会,RR 级别只在事务开始时生成一次,之后始终应用该 ReadView。而 RC 级别则在每次 select 时,都会生成一个 ReadView。

二狗:那 MVCC 解决了幻读了没有?

幻读:在一个事务中应用雷同的 SQL 两次读取,第二次读取到了其余事务新插入的行,则称为产生了幻读。

例如:

1)事务 1 第一次查问:select * from user where id < 10 时查到了 id = 1 的数据

2)事务 2 插入了 id = 2 的数据

3)事务 1 应用同样的语句第二次查问时,查到了 id = 1、id = 2 的数据,呈现了幻读。

谈到幻读,首先咱们要引入“以后读”和“快照读”的概念,聪慧的你肯定通过名字猜出来了:

快照读:生成一个事务快照(ReadView),之后都从这个快照获取数据。一般 select 语句就是快照读。

以后读:读取数据的最新版本。常见的 update/insert/delete、还有 select … for update、select … lock in share mode 都是以后读。

对于快照读,MVCC 因为因为从 ReadView 读取,所以必然不会看到新插入的行,所以人造就解决了幻读的问题。

而对于以后读的幻读,MVCC 是无奈解决的。须要应用 Gap Lock 或 Next-Key Lock(Gap Lock + Record Lock)来解决。

其实原理也很简略,用下面的例子略微批改下以触发以后读:select * from user where id < 10 for update,当应用了 Gap Lock 时,Gap 锁会锁住 id < 10 的整个范畴,因而其余事务无奈插入 id < 10 的数据,从而避免了幻读。

二狗:那常常有人说 Repeatable Read 解决了幻读是什么状况?

SQL 规范中规定的 RR 并不能打消幻读,然而 MySQL 的 RR 能够,靠的就是 Gap 锁。在 RR 级别下,Gap 锁是默认开启的,而在 RC 级别下,Gap 锁是敞开的。

二狗:小伙子不错,大活都给你搞下来了,接下来看下根底扎不扎实。什么是索引?

MySQL 官网对索引的定义为:索引(Index)是帮忙 MySQL 高效获取数据的数据结构。简略的了解,索引相似于字典外面的目录。

二狗:常见的索引类型有哪些?

常见的索引类型有:hash、b 树、b+ 树。

hash:底层就是 hash 表。进行查找时,依据 key 调用 hash 函数取得对应的 hashcode,依据 hashcode 找到对应的数据行地址,依据地址拿到对应的数据。

B 树:B 树是一种多路搜寻树,n 路搜寻树代表每个节点最多有 n 个子节点。每个节点存储 key + 指向下一层节点的指针 + 指向 key 数据记录的地址。查找时,从根结点向下进行查找,直到找到对应的 key。

B+ 树:B+ 树是 b 树的变种,次要区别在于:B+ 树的非叶子节点只存储 key + 指向下一层节点的指针。另外,B+ 树的叶子节点之间通过指针来连贯,形成一个有序链表,因而对整棵树的遍历只须要一次线性遍历叶子结点即可。

二狗:为什么 MySQL 数据库要用 B + 树存储索引?而不必红黑树、Hash、B 树?

红黑树:如果在内存中,红黑树的查找效率比 B 树更高,然而波及到磁盘操作,B 树就更优了。因为红黑树是二叉树,数据量大时树的层数很高,从树的根结点向下寻找的过程,每读 1 个节点,都相当于一次 IO 操作,因而红黑树的 I / O 操作会比 B 树多的多。

hash 索引:如果只查问单个值的话,hash 索引的效率十分高。然而 hash 索引有几个问题:1)不反对范畴查问;2)不反对索引值的排序操作;3)不反对联结索引的最左匹配规定。

B 树索引:B 树索相比于 B + 树,在进行范畴查问时,须要做部分的中序遍历,可能要跨层拜访,跨层拜访代表着要进行额定的磁盘 I / O 操作;另外,B 树的非叶子节点寄存了数据记录的地址,会导致寄存的节点更少,树的层数变高。

二狗:MySQL 中的索引叶子节点寄存的是什么?

MyISAM 和 InnoDB 都是采纳的 B + 树作为索引构造,然而叶子节点的存储上有些不同。

MyISAM:主键索引和辅助索引(一般索引)的叶子节点都是寄存 key 和 key 对应数据行的地址。在 MyISAM 中,主键索引和辅助索引没有任何区别。

InnoDB:主键索引寄存的是 key 和 key 对应的数据行。辅助索引寄存的是 key 和 key 对应的主键值。因而在应用辅助索引时,通常须要检索两次索引,首先检索辅助索引取得主键值,而后用主键值到主键索引中检索取得记录。

二狗:什么是聚簇索引(汇集索引)?

聚簇索引并不是一种独自的索引类型,而是一种数据存储形式。聚簇索引将索引和数据行放到了一块,找到索引也就找到了数据。因为无需进行回表操作,所以效率很高。

InnoDB 中必然会有,且只会有一个聚簇索引。通常是主键,如果没有主键,则优先选择非空的惟一索引,如果惟一索引也没有,则会创立一个暗藏的 row_id 作为聚簇索引。至于为啥会只有一个聚簇索引,其实很简略,因为咱们的数据只会存储一份。

而非聚簇索引则将数据存储和索引离开,找到索引后,须要通过对应的地址找到对应的数据行。MyISAM 的索引形式就是非聚簇索引。

二狗:什么是回表查问?

InnoDB 中,对于主键索引,只须要走一遍主键索引的查问就能在叶子节点拿到数据。

而对于一般索引,叶子节点存储的是 key + 主键值,因而须要再走一次主键索引,通过主键索引找到行记录,这就是所谓的回表查问,先定位主键值,再定位行记录。

二狗:走一般索引,肯定会呈现回表查问吗?

不肯定,如果查问语句所要求的字段全副命中了索引,那么就不用再进行回表查问。

很容易了解,有一个 user 表,主键为 id,name 为一般索引,则再执行:select id, name from user where name = ‘joonwhee’ 时,通过 name 的索引就能拿到 id 和 name 了,因而无需再回表去查数据行了。

二狗:那你晓得什么是笼罩索引(索引笼罩)吗?

笼罩索引是 SQL-Server 中的一种说法,下面讲的例子其实就实现了笼罩索引。具体的:当索引上蕴含了查问语句中的所有列时,咱们无需进行回表查问就能拿到所有的申请数据,因而速度会很快。

当 explain 的输入后果 Extra 字段为 Using index 时,则代表触发笼罩索引。以下面的例子为例:

二狗:联结索引(复合索引)的底层实现?最佳左前缀准则?

联结索引底层还是应用 B + 树索引,并且还是只有一棵树,只是此时的排序会:首先依照第一个索引排序,在第一个索引雷同的状况下,再按第二个索引排序,顺次类推。

这也是为什么有“最佳左前缀准则”的起因,因为左边(前面)的索引都是在右边(后面)的索引排序的根底上进行排序的,如果没有右边的索引,独自看左边的索引,其实是无序的。

还是以字典为例,咱们如果要查第 2 个字母为 k 的,通过目录是无奈疾速找的,因为首字母 A – Z 外面都可能蕴含第 2 个字母为 k 的。

二狗:union 和 union all 的区别

union all:对两个后果集间接进行并集操作,记录可能有反复,不会进行排序。

union:对两个后果集进行并集操作,会进行去重,记录不会反复,按字段的默认规定排序。

因而,从效率上说,UNION ALL 要比 UNION 更快。

二狗:B+ 树中一个节点到底多大适合?

1 页或页的倍数最为适合。因为如果一个节点的大小小于 1 页,那么读取这个节点的时候其实也会读出 1 页,造成资源的节约。所以为了不造成节约,所以最初把一个节点的大小管制在 1 页、2 页、3 页等倍数页大小最为适合。

这里说的“页”是 MySQL 自定义的单位(和操作系统相似),MySQL 的 Innodb 引擎中 1 页的默认大小是 16k,能够应用命令 SHOW GLOBAL STATUS LIKE ‘Innodb_page_size’ 查看。

二狗:那 MySQL 中 B + 树的一个节点大小为多大呢?

在 MySQL 中 B+ 树的一个节点大小为“1 页”,也就是 16k。

二狗:为什么一个节点为 1 页就够了?

Innodb 中,B+ 树中的一个节点存储的内容是:

  • 非叶子节点:key + 指针
  • 叶子节点:数据行(key 通常是数据的主键)

对于叶子节点:咱们假如 1 行数据大小为 1k(对于一般业务相对够了),那么 1 页能存 16 条数据。

对于非叶子节点:key 应用 bigint 则为 8 字节,指针在 MySQL 中为 6 字节,一共是 14 字节,则 16k 能寄存 16 * 1024 / 14 = 1170 个。那么一颗高度为 3 的 B + 树能存储的数据为:1170 * 1170 * 16 = 21902400(千万级)。

所以在 InnoDB 中 B + 树高度个别为 3 层时,就能满足千万级的数据存储。在查找数据时一次页的查找代表一次 IO,所以通过主键索引查问通常只须要 1 - 3 次 IO 操作即可查找到数据。千万级别对于个别的业务来说曾经足够了,所以一个节点为 1 页,也就是 16k 是比拟正当的。

二狗:什么是 Buffer Pool?

Buffer Pool 是 InnoDB 保护的一个缓存区域,用来缓存数据和索引在内存中,次要用来减速数据的读写,如果 Buffer Pool 越大,那么 MySQL 就越像一个内存数据库,默认大小为 128M。

InnoDB 会将那些热点数据和一些 InnoDB 认为行将拜访到的数据存在 Buffer Pool 中,以晋升数据的读取性能。

InnoDB 在批改数据时,如果数据的页在 Buffer Pool 中,则会间接批改 Buffer Pool,此时咱们称这个页为脏页,InnoDB 会以肯定的频率将脏页刷新到磁盘,这样能够尽量减少磁盘 I /O,晋升性能。

二狗:InnoDB 四大个性晓得吗?

插入缓冲(insert buffer):

索引是存储在磁盘上的,所以对于索引的操作须要波及磁盘操作。如果咱们应用自增主键,那么在插入主键索引(聚簇索引)时,只需一直追加即可,不须要磁盘的随机 I/O。然而如果咱们应用的是一般索引,大概率是无序的,此时就波及到磁盘的随机 I/O,而随机 I / O 的性能是比拟差的(Kafka 官网数据:磁盘程序 I / O 的性能是磁盘随机 I / O 的 4000~5000 倍)。

因而,InnoDB 存储引擎设计了 Insert Buffer,对于非汇集索引的插入或更新操作,不是每一次直接插入到索引页中,而是先判断插入的非汇集索引页是否在缓冲池(Buffer pool)中,若在,则直接插入;若不在,则先放入到一个 Insert Buffer 对象中,而后再以肯定的频率和状况进行 Insert Buffer 和辅助索引页子节点的 merge(合并)操作,这时通常能将多个插入合并到一个操作中(因为在一个索引页中),这就大大提高了对于非汇集索引插入的性能。

插入缓冲的应用须要满足以下两个条件:1)索引是辅助索引;2)索引不是惟一的。

因为在插入缓冲时,数据库不会去查找索引页来判断插入的记录的唯一性。如果去查找必定又会有随机读取的状况产生,从而导致 Insert Buffer 失去了意义。

二次写(double write):

脏页刷盘危险:InnoDB 的 page size 个别是 16KB,操作系统写文件是以 4KB 作为单位,那么每写一个 InnoDB 的 page 到磁盘上,操作系统须要写 4 个块。于是可能呈现 16K 的数据,写入 4K 时,产生了零碎断电或零碎解体,只有一部分写是胜利的,这就是 partial page write(局部页写入)问题。这时会呈现数据不残缺的问题。

这时是无奈通过 redo log 复原的,因为 redo log 记录的是对页的物理批改,如果页自身曾经损坏,重做日志也无能为力。

doublewrite 就是用来解决该问题的。doublewrite 由两局部组成,一部分为内存中的 doublewrite buffer,其大小为 2MB,另一部分是磁盘上共享表空间中间断的 128 个页,即 2 个区(extent),大小也是 2M。

为了解决 partial page write 问题,当 MySQL 将脏数据刷新到磁盘的时候,会进行以下操作:

1)先将脏数据复制到内存中的 doublewrite buffer

2)之后通过 doublewrite buffer 再分 2 次,每次 1MB 写入到共享表空间的磁盘上(程序写,性能很高)

3)实现第二步之后,马上调用 fsync 函数,将 doublewrite buffer 中的脏页数据写入理论的各个表空间文件(离散写)。

如果操作系统在将页写入磁盘的过程中产生解体,InnoDB 再次启动后,发现了一个 page 数据曾经损坏,InnoDB 存储引擎能够从共享表空间的 doublewrite 中找到该页的一个最近的正本,用于进行数据恢复了。

自适应哈希索引(adaptive hash index):

哈希(hash)是一种十分快的查找办法,个别状况下查找的工夫复杂度为 O(1)。然而因为不反对范畴查问等条件的限度,InnoDB 并没有采纳 hash 索引,然而如果能在一些非凡场景下应用 hash 索引,则可能是一个不错的补充,而 InnoDB 正是这么做的。

具体的,InnoDB 会监控对表上索引的查找,如果察看到某些索引被频繁拜访,索引成为热数据,建设哈希索引能够带来速度的晋升,则建设哈希索引,所以称之为自适应(adaptive)的。自适应哈希索引通过缓冲池的 B+ 树结构而来,因而建设的速度很快。而且不须要将整个表都建哈希索引,InnoDB 会主动依据拜访的频率和模式来为某些页建设哈希索引。

预读(read ahead):

InnoDB 在 I/O 的优化上有个比拟重要的个性为预读,当 InnoDB 预计某些 page 可能很快就会须要用到时,它会异步地将这些 page 提前读取到缓冲池(buffer pool)中,这其实有点像空间局部性的概念。

空间局部性(spatial locality):如果一个数据项被拜访,那么与他地址相邻的数据项也可能很快被拜访。

InnoDB 应用两种预读算法来进步 I / O 性能:线性预读(linear read-ahead)和随机预读(randomread-ahead)。

其中,线性预读以 extent(块,1 个 extent 等于 64 个 page)为单位,而随机预读放到以 extent 中的 page 为单位。线性预读着眼于将下一个 extent 提前读取到 buffer pool 中,而随机预读着眼于将以后 extent 中的残余的 page 提前读取到 buffer pool 中。

线性预读(Linear read-ahead):线性预读形式有一个很重要的变量 innodb_read_ahead_threshold,能够管制 Innodb 执行预读操作的触发阈值。如果一个 extent 中的被程序读取的 page 超过或者等于该参数变量时,Innodb 将会异步的将下一个 extent 读取到 buffer pool 中,innodb_read_ahead_threshold 能够设置为 0 -64(一个 extend 下限就是 64 页)的任何值,默认值为 56,值越高,拜访模式查看越严格。

随机预读(Random read-ahead): 随机预读形式则是示意当同一个 extent 中的一些 page 在 buffer pool 中发现时,Innodb 会将该 extent 中的残余 page 一并读到 buffer pool 中,因为随机预读形式给 Innodb code 带来了一些不必要的复杂性,同时在性能也存在不稳定性,在 5.5 中曾经将这种预读形式废除。要启用此性能,请将配置变量设置 innodb_random_read_ahead 为 ON。

二狗:说说共享锁和排他锁?

共享锁又称为读锁,简称 S 锁,顾名思义,共享锁就是多个事务对于同一数据能够共享一把锁,都能拜访到数据,然而只能读不能批改。

排他锁又称为写锁,简称 X 锁,顾名思义,排他锁就是不能与其余锁并存,如一个事务获取了一个数据行的排他锁,其余事务就不能再获取该行的其余锁,包含共享锁和排他锁,然而获取排他锁的事务能够对数据就行读取和批改。

常见的几种 SQL 语句的加锁状况如下:

select * from table:不加锁

update/insert/delete:排他锁

select * from table where id = 1 for update:id 为索引,加排他锁

select * from table where id = 1 lock in share mode:id 为索引,加共享锁

二狗:说说数据库的行锁和表锁?

行锁:操作时只锁某一(些)行,不对其它行有影响。开销大,加锁慢;会呈现死锁;锁定粒度小,产生锁抵触的概率低,并发度高。

表锁:即便操作一条记录也会锁住整个表。开销小,加锁快;不会呈现死锁;锁定粒度大,产生锁抵触概率高,并发度最低。

页锁:操作时锁住一页数据(16kb)。开销和加锁速度介于表锁和行锁之间;会呈现死锁;锁定粒度介于表锁和行锁之间,并发度个别。

InnoDB 有行锁和表锁,MyIsam 只有表锁。

二狗:InnoDB 的行锁是怎么实现的?

InnoDB 行锁是通过索引上的索引项来实现的。象征者:只有通过索引条件检索数据,InnoDB 才会应用行级锁,否则,InnoDB 将应用表锁!

对于主键索引:间接锁住锁住主键索引即可。

对于一般索引:先锁住一般索引,接着锁住主键索引,这是因为一张表的索引可能存在多个,通过主键索引能力确保锁是惟一的,不然如果同时有 2 个事务对同 1 条数据的不同索引别离加锁,那就可能存在 2 个事务同时操作一条数据了。

二狗:InnoDB 锁的算法有哪几种?

Record lock:记录锁,单条索引记录上加锁,锁住的永远是索引,而非记录自身。

Gap lock:间隙锁,在索引记录之间的间隙中加锁,或者是在某一条索引记录之前或者之后加锁,并不包含该索引记录自身。

Next-key lock:Record lock 和 Gap lock 的联合,即除了锁住记录自身,也锁住索引之间的间隙。

二狗:MySQL 如何实现乐观锁和乐观锁?

乐观锁:更新时带上版本号(cas 更新)

乐观锁:应用共享锁和排它锁,select…lock in share mode,select…for update。

二狗:InnoDB 和 MyISAM 的区别?

比照项

InnoDB

MyIsam

事务

反对

不反对

锁类型

行锁、表锁

表锁

缓存

缓存索引和数据

只缓存索引

主键

必须有,用于实现聚簇索引

能够没有

索引

B+ 树,主键是聚簇索引

B+ 树,非聚簇索引

select count(*) from table

较慢,扫描全表

贼快,用一个变量保留了表的行数,只需读出该变量即可

hash 索引

反对

不反对

记录存储程序

按主键大小有序插入

按记录插入程序保留

外键

反对

不反对

全文索引

5.7 反对

反对

关注点

事务

性能

二狗:存储引擎的抉择?

没有非凡状况,应用 InnoDB 即可。如果表中绝大多数都只是读查问,能够思考 MyISAM。

二狗:explain 用过吗,有哪些字段别离是啥意思?

explain 字段有:

  • id:标识符
  • select_type:查问的类型
  • table:输入后果集的表
  • partitions:匹配的分区
  • type:表的连贯类型
  • possible_keys:查问时,可能应用的索引
  • key:理论应用的索引
  • key_len:应用的索引字段的长度
  • ref:列与索引的比拟
  • rows:预计要查看的行数
  • filtered:按表条件过滤的行百分比
  • Extra:附加信息

二狗:type 中有哪些常见的值?

按类型排序,从好到坏,常见的有:const > eq_ref > ref > range > index > ALL。

  • const:通过主键或惟一键查问,并且后果只有 1 行(也就是用等号查问)。因为仅有一行,所以优化器的其余部分能够将这一行中的列值视为常量。
  • eq_ref:通常呈现于两表关联查问时,应用主键或者非空惟一键关联,并且查问条件不是主键或惟一键的等号查问。
  • ref:通过一般索引查问,并且应用的等号查问。
  • range:索引的范畴查找(>=、<、in 等)。
  • index:全索引扫描。
  • All:全表扫描

二狗:explain 次要关注哪些字段?

次要关注 type、key、row、extra 等字段。次要是看是否应用了索引,是否扫描了过多的行数,是否呈现 Using temporary、Using filesort 等一些影响性能的次要指标。

二狗:如何做慢 SQL 优化?

首先要搞明确慢的起因是什么:是查问条件没有命中索引?还是 load 了不须要的数据列?还是数据量太大?所以优化也是针对这三个方向来的。

  • 首先用 explain 剖析语句的执行打算,查看应用索引的状况,是不是查问没走索引,如果能够加索引解决,优先采纳加索引解决。
  • 剖析语句,看看是否存在一些导致索引生效的用法,是否 load 了额定的数据,是否加载了许多后果中并不需要的列,对语句进行剖析以及重写。
  • 如果对语句的优化曾经无奈进行,能够思考表中的数据量是否太大,如果是的话能够进行垂直拆分或者程度拆分。

二狗:说说 MySQL 的主从复制?

MySQL 主从复制波及到三个线程,一个运行在主节点(Log Dump Thread),其余两个(I/O Thread,SQL Thread)运行在从节点,如下图所示

主从复制默认是异步的模式,具体过程如下。

1)从节点上的 I /O 线程连贯主节点,并申请从指定日志文件(bin log file)的指定地位(bin log position,或者从最开始的日志)之后的日志内容;

2)主节点接管到来自从节点的 I/ O 申请后,读取指定文件的指定地位之后的日志信息,返回给从节点。返回信息中除了日志所蕴含的信息之外,还包含本次返回的信息的 bin-log file 以及 bin-log position;从节点的 I/O 过程接管到内容后,将接管到的日志内容更新到 relay log 中,并将读取到的 bin log file(文件名)和 position(地位)保留到 master-info 文件中,以便在下一次读取的时候可能分明的通知 Master“我须要从某个 bin-log 的哪个地位开始往后的日志内容”;

3)从节点的 SQL 线程检测到 relay-log 中新减少了内容后,会解析 relay-log 的内容,并在本数据库中执行。

二狗:异步复制,主库宕机后,数据可能失落?

能够应用半同步复制或全同步复制。

半同步复制:

批改语句写入 bin log 后,不会立刻给客户端返回后果。而是首先通过 log dump 线程将 binlog 发送给从节点,从节点的 I/O 线程收到 binlog 后,写入到 relay log,而后返回 ACK 给主节点,主节点 收到 ACK 后,再返回给客户端胜利。

半同步复制的特点:

  • 确保事务提交后 binlog 至多传输到一个从库
  • 不保障从库利用完这个事务的 binlog
  • 性能有肯定的升高,响应工夫会更长
  • 网络异样或从库宕机,卡主主库,直到超时或从库复原

全同步复制:主节点和所有从节点全副执行了该事务并确认才会向客户端返回胜利。因为须要期待所有从库执行完该事务能力返回,所以全同步复制的性能必然会收到重大的影响。

二狗:主库写压力大,从库复制很可能呈现提早?

能够应用并行复制(并行是指从库多个 SQL 线程并行执行 relay log),解决从库复制提早的问题。

MySQL 5.7 中引入基于组提交的并行复制,其核心思想:一个组提交的事务都是能够并行回放,因为这些事务都已进入到事务的 prepare 阶段,则阐明事务之间没有任何抵触(否则就不可能提交)。

判断事务是否处于一个组是通过 last_committed 变量,last_committed 示意事务提交的时候,上次事务提交的编号,如果事务具备雷同的 last_committed,则示意这些事务都在一组内,能够进行并行的回放。

正文完
 0