学MySQL,这篇万字总结,真的够用了

百家 作者:51CTO技巧栈 2020-01-14 18:50 浏览:85 评论:0

这篇文章将从查询缓存,索引,优化器,explain,redo 日记,undo 日记,事务隔离级别,锁等方面来讲解 MySQL。

学MySQL,这篇万字总结,真的够用了-爱尖刀

图片来自 Pexels

残局一张图

学MySQL,这篇万字总结,真的够用了-爱尖刀

这张图是重点!!!咱要先对 MySQL 有一个宏不雅的懂得,知道他的履行流程。

一条 SQL 语句过去的流程是甚么样的?

①当客户端连接到 MySQL 办事器时,办事器对其停止认证。可以经过过程用户名与暗码认证,也能够经过过程 SSL 证书停止认证。登录认证后,办事器还会验证客户端能否有履行某个查询的操作权限。

②在正式查询之前,办事器会检查查询缓存,假设能找到对应的查询,则不用停止查询解析,优化,履行等过程,直接前往缓存中的成果集。

③MySQL 的解析器会根据查询语句,构造出一个解析树,重要用于根据语律例则来验证语句能否精确,比如 SQL 的关键字能否精确,关键字的次序能否精确。而预处理器主如果进一步校验,比如表名,字段名能否精确等。

④查询优化器将解析树转化为查询筹划,普通情况下,一条查询可以有很多种履行方法,终究前往雷同的成果,优化器就是根据本钱找到这个中最优的履行筹划。

⑤履行筹划调用查询履行引擎,而查询引擎经过过程一系列 API 接口查询到数据。

⑥取得数据以后,在前往给客户真个同时,会将数据存在查询缓存中。

查询缓存

我们先经过过程 show variables like '%query_cache%' 来看一下默许的数据库设备,此为本地数据库的设备。

学MySQL,这篇万字总结,真的够用了-爱尖刀

概念

①have_query_cache:以后的 MySQL 版天性否支撑“查询缓存”功能。

②query_cache_limit:MySQL 可以或许缓存的最大年夜查询成果,查询成果大年夜于该值时不会被缓存。默许值是 1048576(1MB)。

③query_cache_min_res_unit:查询缓存分派的最小块(字节)。默许值是 4096(4KB)。

当查询停止时,MySQL 把查询成果保存在 query cache,然则假设保存的成果比较大年夜,逾越了 query_cache_min_res_unit 的值,这时候辰 MySQL 将一边检索成果,一边停止保存成果。

他保存成果也是按默许大年夜小先分派一块空间,假设不敷,又要请求新的空间给他。

假设查询成果比较小,默许的 query_cache_min_res_unit 能够形成大年夜量的内存碎片,假设查询成果比较大年夜,默许的 query_cache_min_res_unit 又不敷,招致一向分派块空间。

所以可以根据实际需求,调理 query_cache_min_res_unit 的大年夜小。

注:假设下面说的内容有点弯弯绕,那举个实际生活中的例子,比如咱如今要给活动员送水,默许的是 500ml 的瓶子,假设过去的是少年活动员,能够 500ml 太大年夜了,他们喝不完,形成了浪费。

那我们便可以选择 300ml 的瓶子,假设过去的是成年活动员,能够 500ml 不敷,那他们一瓶喝完了,又开一瓶,直接不渴为止。那么那样开瓶子也要时间,我们便可以选择 1000ml 的瓶子。

④query_cache_size:为缓存查询成果分派的总内存。

⑤query_cache_type:默许为 on,可以缓存除以 select sql_no_cache 开首的一切查询成果。

⑥query_cache_wlock_invalidate:假设该表被锁住,能否前往缓存中的数据,默许是封闭的。

道理

MySQL 的查询缓存本质上是缓存 SQL 的 Hash 值和该 SQL 的查询成果,假设运转雷同的 SQL,办事器直接从缓存中去掉落成果,而不再去解析,优化,寻觅最低本钱的履行筹划等一系列操作,大年夜大年夜晋升了查询速度。

然则万事有益也有弊:

第一个弊病就是假设表的数据有一条产生变更,那么缓存好的成果将全部不再有效。这关于频繁更新的表,查询缓存是不合适的。

比如一张表外面只要两个字段,分别是 id 和 name,数据有一条为 1,张三。

我应用 select * from 表名 where name=“张三”来停止查询,MySQL 发明查询缓存中没有此数据,会停止一系列的解析,优化等操作停止数据的查询。

查询停止以后将该 SQL 的 Hash 和查询成果缓存起来,并将查询成果前往给客户端。

然则这个时辰我又新增了一条数据 2,张三。假设我还用雷同的 SQL 来履行,他会根据该 SQL 的 Hash 值去查询缓存中,那么成果就错了。

所以 MySQL 关于数据有变更的表来讲,会直接清空关于该表的一切缓存。如许其实效力是很差的。

第二个弊病就是缓存机制是经过过程对 SQL 的 Hash,得出的值为 Key,查询成果为 Value 来存放的,那么就意味着 SQL 必须完完全全如出一辙,不然就命不中缓存。

我们都知道 Hash 值的规矩,就算很小的查询,哈希出来的成果差距是很多的,所以 select * from 表名 where name=“张三”和SELECT * FROM 表名 WHERE NAME=“张三”和select * from 表名 where name = “张三”,三个SQL 哈希出来的值是不一样的。

大年夜小写和空格影响了他们,所以其实不克不及射中缓存,但其实他们搜刮成果是完全一样的。

临盆若何设置 MySQL Query Cache

先来看线上参数:
学MySQL,这篇万字总结,真的够用了-爱尖刀

我们发明将 query_cache_type 设置为 OFF,其实网上材料和各大年夜云厂商供给的云办事器都是将这个功能封闭的,从下面的道理来看,在普通情况下,他的弊病大年夜于长处。

索引

例子:创建一个名为 user 的表,其包含 id,name,age,sex 等字段信息。另外,id 为主键聚簇索引,idx_name 为非聚簇索引。

CREATE TABLE `user` (
  `id` varchar(10NOT NULL DEFAULT '',
  `name` varchar(10DEFAULT NULL,
  `age` int(11DEFAULT NULL,
  `sex` varchar(10DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_name` (`name`USING BTREE
ENGINE=InnoDB DEFAULT CHARSET=utf8;
我们将其设置 10 条数据,便于下面的索引的懂得:
INSERT INTO `user` VALUES ('1''andy''20''女');
INSERT INTO `user` VALUES ('10''baby''12''女');
INSERT INTO `user` VALUES ('2''kat''12''女');
INSERT INTO `user` VALUES ('3''lili''20''男');
INSERT INTO `user` VALUES ('4''lucy''22''女');
INSERT INTO `user` VALUES ('5''bill''20''男');
INSERT INTO `user` VALUES ('6''zoe''20''男');
INSERT INTO `user` VALUES ('7''hay''20''女');
INSERT INTO `user` VALUES ('8''tony''20''男');
INSERT INTO `user` VALUES ('9''rose''21''男');

聚簇索引(主键索引)

先来一张图镇楼,接上去就是看图措辞:
学MySQL,这篇万字总结,真的够用了-爱尖刀

他包含两个特点:

  • 应用记录主键值的大年夜小来停止记录和页的排序。页内的记录是按照主键的大年夜小次序排成一个单项链表。各个存放用户记录的页也是根据页中用户记录的主键大年夜小次序排成一个双向链表。

  • 叶子节点存储的是完全的用户记录。

注:聚簇索引不须要我们显示的创建,他是由 InnoDB 存储引擎主动为我们创建的。假设没有主键,其也会默许创建一个。

非聚簇索引(二级索引)

下面的聚簇索引只能在搜刮条件是主键时才能发挥感化,由于聚簇索引可以根据主键停止排序的。

假设搜刮条件是 name,在刚才的聚簇索引上,我们能够遍历,挨个找到符合条件的记录,然则,如许真的是太蠢了,MySQL 不会如许做的。

假设我们想让搜刮条件是 name 的时辰,也能应用索引,那可以多创建一个基于 name 的二叉树,以下图:
学MySQL,这篇万字总结,真的够用了-爱尖刀

他与聚簇索引的不合:

  • 叶子节点外部应用 name 字段排序,叶子节点之间也是应用 name 字段排序。

  • 叶子节点不再是完全的数据记录,而是 name 和主键值。

为甚么不再是完全信息?MySQL 只让聚簇索引的叶子节点存放完全的记录信息,由于假设有好几个非聚簇索引,他们的叶子节点也存放完全的记录绩效,那就不浪费空间啦。

假设我搜刮条件是基于 name,须要查询一切字段的信息,那查询过程是啥?

  • 根据查询条件,采取 name 的非聚簇索引,先定位到该非聚簇索引某些记录行。

  • 根据记录行找到照应的 id,再根据 id 到聚簇索引中找到相干记录。这个过程叫做回表。

结合索引

图就不画了,简单来讲,假设 name 和 age 构成一个结合索引,那么先按 name 排序,假设 name 一样,就按 age 排序。

一些准绳

①最左前缀准绳。一个结合索引(a,b,c),假设有一个查询条件有 a,有 b,那么他则走索引,假设有一个查询条件没有 a,那么他则不走索引。

②应用唯一索引。具有多个反复值的列,其索引后果最差。例如,存放姓名的列具有不合值,很轻易辨别每行。

而用来记录性其他列,只含有“男”,“女”,不论搜刮哪个值,都邑得出大年夜约一半的行,如许的索引对性能的晋升不敷高。

③不要过度索引。每个额外的索引都要占用额外的磁盘空间,并降低写操作的性能。

在修改表的内容时,索引必须停止更新,有时能够须要重构,是以,索引越多,所花的时间越长。

④索引列不克不及参与计算,保持列“干净”,比如 from_unixtime(create_time) = ’2014-05-29’就不克不及应用到索引。

缘由很简单,B+ 树中存的都是数据表中的字段值,但停止检索时,须要把一切元素都应用函数才能比较,明显本钱太大年夜。

所以语句应当写成:
create_time = unix_timestamp(’2014-05-29’);

⑤必定要设置一个主键。前面聚簇索引说到假设不指定主键,InnoDB 会主动为其指定主键,这个我们是看不见的。

反正都要生成一个主键的,还不如我们设置,今后在某些搜刮条件时还能用到主键的聚簇索引。

⑥主键推荐用自增 id,而不是 uuid。下面的聚簇索引说到每页数据都是排序的,并且页之间也是排序的,假设是 uuid,那么其肯定是随机的,其能够从中心拔出,招致页的决裂,产生很多表碎片。

假设是自增的,那么其有从小到大年夜自增的,有次序,那么在拔出的时辰就添加到以后索引的后续地位。当一页写满,就会主动开辟一个新的页。

注:假设自增 id 用完了,那将字段类型改成 bigint,就算每秒 1 万条数据,跑 100 年,也没达到 bigint 的最大年夜值。

万年面试题(为甚么索援用 B+ 树)

①B+ 树的磁盘读写价值更低:B+ 树的外部节点并没有指向关键字详细信息的指针,是以其外部节点相对 B 树更小。

假设把一切同一外部节点的关键字存放在同一盘块中,那么盘块所能包容的关键字数量也越多,一次性读入内存的须要查找的关键字也就越多,相对 IO 读写次数就降低了。

②由于 B+ 树的数据都存储在叶子结点中,分支结点均为索引,便利扫库,只须要扫一遍叶子结点便可。

然则 B 树由于其分支结点异样存储着数据,我们要找到详细的数据,须要停止一次中序遍历按序来扫,所以 B+ 树加倍合适在区间查询的情况,所以平日 B+ 树用于数据库索引。

优化器

在开篇的图外面,我们知道了 SQL 语句从客户端经过搜集协定到查询缓存,假设没有射中缓存,再经过解析任务,取得精确的 SQL,如今就离开了我们这模块说的优化器。

起首,我们知道每条 SQL 都有不合的履行办法,要不经过过程索引,要不经过过程全表扫描的方法。

那么成绩就来了,MySQL 是若何选择时间最短,占用内存最小的履行办法呢?

甚么是本钱?

  • I/O 本钱。数据存储在硬盘上,我们想要停止某个操作须要将其加载到内存中,这个过程的时间被称为 I/O 本钱。默许是 1。

  • CPU 本钱。在内存对成果集停止排序的时间被称为 CPU 本钱。默许是 0.2。

单表查询的本钱

先来建一个用户表 dev_user,外面包含主键 id,用户名 username,暗码 password,外键 user_info_id,状况 status,外键 main_station_id,能否外网拜访 visit,这七个字段。

索引有两个,一个是主键的聚簇索引,另外一个是显式添加的以 username 为字段的唯一索引 uname_unique。
学MySQL,这篇万字总结,真的够用了-爱尖刀

假设搜刮条件是 select * from dev_user where username='XXX',那么 MySQL 是若何选择相干索引呢?

①应用一切能够用到的索引

我们可以看到搜刮条件 username,所以能够走 uname_unique 索引。也能够做聚簇索引,也就是全表扫描。

②计算全表扫描价值

我们经过过程 show table status like ‘dev_user’敕令知道 rows 和 data_length 字段,以下图:

学MySQL,这篇万字总结,真的够用了-爱尖刀

rows:表示表中的记录条数,然则这个数据不精确,是个估计值。

data_length:表示表占用的存储空间字节数。data_length=聚簇索引的页面数量 X 每个页面的大年夜小。

反推出页面数量=1589248÷16÷1024=97:

  • I/O 本钱:97X1=97

  • CPU 本钱:6141X0.2=1228

  • 总本钱:97+1228=1325

③计算应用不合索引履行查询的价值

由于要查询出满足条件的一切字段信息,所以要推敲回表本钱:

  • I/O 本钱=1+1X1=2(范围区间的数量+估计二级记录索引条数)

  • CPU 本钱=1X0.2+1X0.2=0.4(读取二级索引的本钱+回表聚簇索引的本钱)

  • 总本钱= I/O 本钱+CPU 本钱=2.4

④比较各类履行筹划的价值,找出本钱最低的那个

下面两个数字一比较,本钱是采取 uname_unique 索引本钱最低。

多表查询的本钱

关于两表连接查询来讲,他的查询本钱由下面两个部分构成:

  • 单次查询驱动表的本钱

  • 屡次查询被驱动表的本钱(详细查询屡次取决于对驱动表查询的成果集有若干个记录)

index dive

假设前面的搜刮条件不是等值,而是区间,如 select * from dev_user where username>'admin' and username<'test' 这个时辰我们是没法看出须要回表的数量。

步调 1:先根据 username>'admin' 这个条件找到第一笔记录,称为区间最左记录。

步调 2:再根据 username<'test' 这个条件找到最后一笔记录,称为区间最右记录。

步调 3:假设区间最左记录和区间最右记录相差不是很远,可以精确统计出须要回表的数量。

假设相差很远,就先计算 10 页有若干笔记录,再乘以页面数量,终究模糊统计出来。

Explain

学MySQL,这篇万字总结,真的够用了-爱尖刀

产品来索命:

  • 产品:为甚么这个页面出来这么慢?

  • 开辟:由于你查的数据多呗,他就是这么慢

  • 产品:我不论,我要这个页面快点,你如许,客户怎样用啊

  • 开辟:......你行你来

哈哈哈哈,不瞎 BB 啦,假设有些 SQL 贼慢,我们须要知道他有没有走索引,走了哪个索引,这个时辰我就须要经过过程 explain 关键字来深刻懂得 MySQL 外部是若何履行的。
学MySQL,这篇万字总结,真的够用了-爱尖刀

id:普通来讲一个 select 一个唯一 id,假设是子查询,就有两个 select,id 是不一样的,然则凡事有例外,有些子查询的,他们 id 是一样的。

学MySQL,这篇万字总结,真的够用了-爱尖刀
这是为甚么呢?那是由于 MySQL 在停止优化的时辰曾经将子查询改成了连接查询,而连接查询的 id 是一样的。

select_type:

  • simple:不包含 union 和子查询的查询都算 simple 类型。

  • primary:包含 union,union all,个中最左边的查询即为 primary。

  • union:包含 union,union all,除最左边的查询,其他的查询类型都为 union。

table:显示这一行是关于哪张表的。

type 拜访办法:

  • ref:浅显二级索引与常量停止等值婚配

  • ref_or_null:浅显二级索引与常量停止等值婚配,该索引能够是 null

  • const:主键或唯一二级索引列与常量停止等值婚配

  • range:范围区间的查询

  • all:全表扫描

possible_keys:对某表停止单表查询时能够用到的索引。

key:经过查询优化器计算不合索引的本钱,终究选择本钱最低的索引。

rows:

  • 假设应用全表扫描,那么 rows 就代表须要扫描的行数

  • 假设应用索引,那么 rows 就代表估计扫描的行数

filtered:

  • 假设全表扫描,那么 filtered 就代表满足搜刮条件的记录的满分比

  • 假设是索引,那么 filtered 就代表除去索引对应的搜刮,其他搜刮条件的百分比

redo 日记(物理日记)

InnoDB 存储引擎是以页为单位来管理存储空间的,我们停止的增删改查操作都是将页的数据加载到内存中,然落先行操作,再将数据刷回到硬盘上。
那么成绩就来了,假设我要给张三转账 100 块钱,事务曾经提交了,这个时辰 InnoDB 把数据加载到内存中,这个时辰还没来得及刷入硬盘,忽然停电了,数据库崩了。

重启以后,发明我的钱没有转成功,这不是难堪了吗?
处理办法很明显,我们在硬盘加载到内存以后,停止一系列操作,一顿操作猛如虎,还未刷新到硬盘之前,先记录下,在 XXX 地位我的记录中金额减 100,在 XXX 地位张三的记录中金额加 100。

然后再停止增删改查操作,最后刷入硬盘。假设未刷入硬盘,在重启以后,先加载之前的记录,那么数据就回来了。
这个记录就叫做重做日记,即 redo 日记。他的目标是想让曾经提交的事务对数据的修改是永久的,就算他重启,数据也能恢复出来。

log buffer(日记缓冲区)

为懂得决磁盘速度过慢的成绩,redo 日记不克不及直接写入磁盘,咱先整一大年夜片持续的内存空间给他放数据。

这一大年夜片内存就叫做日记缓冲区,即 log buffer。到了合适的时辰,再刷入硬盘。至于甚么时辰是合适的,这个下一章节说。

我们可以经过过程 show VARIABLES like 'innodb_log_buffer_size' 敕令来检查以后的日记缓存大年夜小。

下图为线上的大年夜小:

学MySQL,这篇万字总结,真的够用了-爱尖刀

redo 日记刷盘机会

由于 redo 日记一向都是增长的,且内存空间无限,数据也不克不及一向待在缓存中,
我们须要将其刷新至硬盘上。 

那甚么时辰刷新到硬盘呢?
  • log buffer 空间缺乏。下面有指定缓冲区的内存大年夜小,MySQL 认为日记量曾经占了
    总容量的一半阁下,就须要将这些日记刷新到磁盘上。 

  • 事务提交时。我们应用 redo 日记的目标就是将他未刷新到磁盘的记录保存起来,防止损掉,假设数据提交了,我们是可以不把数据提交到磁盘的,但为了包管耐久性,必须
    把修改这些页面的 redo 日记刷新到磁盘。 

  • 后台线程不合的刷新后台有一个线程,大年夜概每秒都邑将 log buffer 外面的 redo 日记刷新到硬盘上。

  • checkpoint 下下末节讲。

redo 日记文件组

我们可以经过过程 show variables like 'datadir' 敕令找到相干目次,底下有两个文件,分别是 ib_logfile0 和 ib_logfile1,以下图所示:

学MySQL,这篇万字总结,真的够用了-爱尖刀

学MySQL,这篇万字总结,真的够用了-爱尖刀

我们将缓冲区 log buffer 外面的 redo 日记刷新到这个两个文件外面,他们写入的方法
是轮回写入的,先写 ib_logfile0,再写 ib_logfile1,等 ib_logfile1 写满了,再写 ib_logfile0。 

那如许就会存在一个成绩,假设 ib_logfile1 写满了,再写 ib_logfile0,之前 ib_logfile0 的内容
不就被覆盖而损掉了吗?这就是 checkpoint 的任务啦。

checkpoint

redo 日记是为了体系崩溃后恢复脏页用的,假设这个脏页可以被刷新到磁盘上,那么
他便可以功成身退,被覆盖也就没事啦。

抵触补习:从体系运转开端,就赓续的修改页面,会赓续的生成 redo 日记。

redo 日记是赓续递增的,MySQL 为其取了一个名字日记序列号 Log Sequence Number,简称 lsn。他的初始化的值为 8704,用来记录以后一共生成了若干 redo 日记。

redo 日记是先写入 log buffer,以后才会被刷新到磁盘的 redo 日记文件。MySQL 为其取了一个名字 flush_to_disk_lsn。

用来解释缓存区中有若干的脏页数据被刷新到磁盘上啦。他的初始值和 lsn 一样,前面的差距就有了。
做一次 checkpoint 分为两步:
  • 计算以后体系可以被覆盖的 redo 日记对应的 lsn 最大年夜值是若干。redo 日记可以被覆盖,意味着他对应的脏页被刷新到磁盘上。

    只需我们计算出以后体系中最早被修改的 oldest_modification,只需体系中 lsn 小于该节点的 oldest_modification 值,磁盘的 redo 日记都是可以被覆盖的。

  •  将 lsn 过程当中的一些数据统计。

undo 日记

undo log 有两个感化:供给回滚和多个行版本控制(MVCC

undo log 和 redo log 记录物理日记不一样,它是逻辑日记。
可以认为当 delete 一笔记录时,undo log 中会记录一条对应的 insert 记录,反之亦然,当 update 一笔记录时,它记录一条对应相反的 update 记录。

举个例子:

insert into a(idvalues(1);(redo)

这笔记录是须要回滚的。回滚的语句是:

delete from a where id = 1;(undo)

试想想看:假设没有做 insert into a(id) values(1);(redo),那么 delete from a where id = 1;(undo) 这句话就没成心义了。

如今看下精确的恢复:

  • 先 insert into a(id) values(1);(redo)

  • 然后 delete from a where id = 1;(undo)

  • 体系就回到了本来的状况,没有这笔记录了

存储方法:是存在段当中。

事务

事务中有一个隔离性特点,实际上在某个事务对某个数据停止拜访时,其他事务应当排序,当该事务提交以后,其他事务才能持续拜访这个数据。

然则如许子对性能影响太大年夜,我们既想保持事务的隔离性,又想让办事器在出来多个事务时性能尽可能高些,所以只能舍弃一部分隔离性而去性能。

事务并发履行的成绩:

①脏写:这个太严重了,任何隔离级别都不准可产生)。

  • sessionA:修改了一条数据,回滚掉落

  • sessionB:修改了同一条数据,提交掉落

关于 sessionB 来讲,明明数据更新了也提交了事务,不克不及说本身啥都没干。

②脏读:一个事务读到另外一个未提交事务修改的数据。

  • session A:查询,取得某条数据

  • session B:修改某条数据,然则最后回滚掉落啦

  • session A:在 sessionB 修改某条数据以后,在回滚之前,读取了该笔记录

关于 session A 来讲,读到了 session 回滚之前的脏数据。

③弗成反复读:前后屡次读取,同一个数据内容不一样。

  • session A:查询某笔记录

  • session B : 修改该笔记录,并提交事务

  • session A : 再次查询该笔记录,发明前后查询不分歧

④幻读:前后屡次读取,数据总量不分歧。

  • session A:查询表内一切记录

  • session B:新增一笔记录,并查询表内一切记录

  • session A:再次查询该笔记录,发明前后查询不分歧

数据库都有的四种隔离级别,MySQL 事务默许的隔离级别是可反复读,并且 MySQL 可以处理了幻读的成绩:
  • 未提交读:脏读,弗成反复读,幻读都有能够产生

  • 已提交读:弗成反复读,幻读能够产生

  • 可反复读:幻读能够产生

  • 可串行化:都弗成能产生

凡是事没有百分百,emmmm,其实 MySQL 并没有百分之百处理幻读的成绩。

学MySQL,这篇万字总结,真的够用了-爱尖刀
举个例子:
  • session A:查询某条不存在的记录。

  • session B:新增该条不存在的记录,并提交事务。

  • session A:再次查询该条不存在的记录,是查询不出来的,然则假设我测验测验修改该笔记录,并提交,其实他是可以修改成功的。

MVCC

版本链:关于该记录的每次更新,都邑将值放在一条 undo 日记中,算是该记录的一个旧版本,随着更新次数的增多,一切版本都邑被 roll_pointer 属性连接成一个链表,即为版本链。
readview:
  • 未提交读:由于可以读到未提交事务修改的记录,所以可以直接读取记录的最新版本就行

  • 已提交读:每次读取之前都生成一个 readview

  • 可反复读:只要在第一次读取的时辰才生成 readview

  • 可串行化:InnoDB 触及了加锁的方法来拜访记录

参考文献:

  • 【原创】面试官:讲讲 MySQL 表设计要留意啥

  • 【原创】杂谈自增主键用完了怎样办

  • MySQL 是如何运转的:从根儿上懂得 MySQL

  • 详细分析 MySQL 事务日记(redo log 和 undo log)

作者:进修 Java 的蜜斯姐

编辑:陶家龙、孙淑娟

出处:转载自微信公众号进修 Java 的蜜斯姐(ID:huangtest01)

学MySQL,这篇万字总结,真的够用了-爱尖刀

出色文章推荐:

三次握手+四次挥手,一文弄定一切!

MySQL性能优化之骨灰级,高阶神技 !

大年夜牛总结的MySQL锁优化,写得太好了!


51CTO技巧栈 51CTO技巧栈
  • 作者暂未设置特性签名
存眷搜集尖刀微信公众号
随时控制互联网出色
告白赞助