BinZhiZhu's Blog

Hello,World.


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 搜索

post一条SQL更新语句是如何执行的?

发表于 2020-02-23 | | 阅读次数:
字数统计: 874 | 阅读时长 ≈ 3
1
例子:update T set c=c+1 where id=2

与查询流程不一样的是,更新流程还涉及两个重要的日志模块,它们正是我们今天要讨论 的主角:redo log(重做日志)和 binlog(归档日志)。如果接触 MySQL,那这两个词 肯定是绕不过的,我后面的内容里也会不断地和你强调。不过话说回来,redo log 和 binlog 在设计上有很多有意思的地方,这些设计思路也可以用到你自己的程序里。

重要的日志模块:redo log(物理日志)

1.核心要点:其实就是 MySQL 里经常说到的 WAL 技术,WAL 的全称 是 Write-Ahead Logging。也就是先记日志,再写到磁盘。具体来说,当有一条记录需要更新的时候,InnoDB 引擎就会先把记录写到redo log里面,并更新内存,这个时候更新就算完成了。同时,InnoDB 引擎会在适当的时候,将这个操作记录更新到磁盘里面,而这个更新往往是在系统比较空闲的时候做。
InnoDB的redo log是有固定大小的,例如可以一组配置4个文件,每个文件也有固定的大小,例如1GB,那么这一组就共有4GB内存(结合粉板理解)。写日志是从头开始写,写到末尾又开始回到开头循环写(大致就是顺时针的时钟概念)。主要操作分为:write pos和checkpoint,前者是写日志,后者理解为擦粉板,write pos 和 checkpoint 之间的是“粉板”上还空着的部分,可以用来记录新的操作。如 果 write pos 追上 checkpoint,表示“粉板”满了,这时候不能再执行新的更新,得停下 来先擦掉一些记录,把 checkpoint 推进一下。
有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢 失,这个能力称为crash-safe。
2.将 redo log 的写入拆成了两个步骤: prepare 和 commit,这就是”两阶段提交”。执行器写完binlog之后,redo log执行commit操作。

重要的日志模块:binlog (逻辑归档日志)

binlog是Server层自己的日志,没有crash-safe能力,后来有了InnoDB插件引擎,补充了这个能力,也就是实现了redo log日志系统。

两种日志的对比

  1. redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎 都可以使用。
  2. redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如“给 ID=2 这一行的 c 字段加 1 ”。
  3. redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指binlog文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

小结

redo log 用于保证 crash-safe 能力。innodb_flush_log_at_trx_commit 这个参数设置成 1 的时候,表示每次事务的 redo log 都直接持久化到磁盘。这个参数我建议你设置成 1, 这样可以保证 MySQL 异常重启之后数据不丢失。
sync_binlog 这个参数设置成 1 的时候,表示每次事务的 binlog 都持久化到磁盘。这个 参数我也建议你设置成 1,这样可以保证 MySQL 异常重启之后 binlog 不丢失。

一条SQL查询语句是如果执行的

发表于 2020-02-22 | | 阅读次数:
字数统计: 888 | 阅读时长 ≈ 3

一条sql查询语句是如果执行的?

总体来说,MySQL大致分为server层和存储引擎层两大部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
explain SELECT * FROM T

### 执行过程
starting 0.0001660 10.573
Executing hook on transaction 0.0000140 0.892
starting 0.0000150 0.955
checking permissions 0.0000140 0.892
Opening tables 0.0002590 16.497
init 0.0000160 1.019
System lock 0.0000220 1.401
optimizing 0.0000140 0.892
statistics 0.0000200 1.274
preparing 0.0000200 1.274
Creating tmp table 0.0000540 3.439
executing 0.0004860 30.955
Sending data 0.0001190 7.580
end 0.0000140 0.892
query end 0.0000150 0.955
removing tmp table 0.0000160 1.019
query end 0.0000130 0.828
removing tmp table 0.0000150 0.955
query end 0.0000120 0.764
closing tables 0.0000130 0.828
freeing items 0.0001760 11.210
cleaning up 0.0000770 4.904

Server层

包括连接器、查询缓存、分析器、优化器、执行器等,所有跨存储引擎的功能都在这一层实现,例如:存储过程、触发器、视图等。

连接器

1.客户端与服务端建立连接,完成tcp三次握手之后,就执行ACL鉴权;
2.连接成功后,可通过:show processlist;来查看连接状态;
3.尽量使用长连接;
4.连接断开才会释放资源;
5.如果不断的建立连接,会占用太多的内存,导致OOM(内存溢出),会被系统强制kill掉,这种情况就是MySQL异常重启了;
6.上诉5的解决方案:1.定期断开连接,按需重连;2.MySQL5.7+版本,可通过:mysql_reset_connection来重新初始化连接资源,这个过程不需要重新ACL鉴权,而是会直接回到最初的连接状态。

查询缓存

1.k-v对的形式缓存,即是:查询语句+查询结果;
2.基本就是getOrSet的过程,找得到直接返回,找不到则执行查询,将执行结果缓存起来;
3.不能滥用SQL_CACHE,每次更新会清空建立的缓存,静态表推荐使用,频繁更新的不推荐使用,后者命中缓存的几率很低,基本都是走执行过程了。

分析器

举例子简单的sql语句:
select * from T where id = 1;
1.词法分析。MySQL会从输入的语句中的’select’这个关键字做识别,认为这是一条查询语句,继续会被T解析成表名T,id则会被识别为列ID;
2.语法分析。通过一系列的语法去检验sql语句是否满足MySQL的语法要求,如果语法错误则会出现SQL syntax error错误;

优化器

select * from t1 join t2 using(ID) where t1.c=10 and t2.d=20;
1.决定使用哪个索引;
2.决定连接顺序,确认用哪种执行方案。例如:先查t1后t2,先t2后t1,这里方案是一致的,但是效率可能不同。
3.进入执行阶段;

执行器

分析器已经告诉你了需要查询还是更新,优化器也决定了使用哪种方案,然后就准备执行语句了。
1.判断是否有执行查询语句权限;
2.在工程上,如果命中了缓存,会在返回结果前做权限验证,查询也会在优化器前做precheck验证权限。
3.如果有权限,那么就开始打开表,执行器会根据表定义的engine引擎,使用这个引擎提供的查询接口。

存储引擎

主要是负责数据的存储以及提取咯。其架构是插件式的,支持InnoDB、MyISAM、Memory等多个存储引擎,mysql v-5.5.5版本,InnoDB开始成为了默认的引擎。
可以通过:engine=存储引擎 的方式来指定存储引擎。

PHP学习笔记

发表于 2019-11-16 | | 阅读次数:
字数统计: 0 | 阅读时长 ≈ 1

希望人人都没有疾病的困扰

发表于 2019-10-18 | | 阅读次数:
字数统计: 856 | 阅读时长 ≈ 2

前几天被告知,自己的一个好友因得抑郁症选择了结束自己的生命。

我得到这个消息之后,我硬是楞了快一分钟我才缓过来,然后跟我那个朋友说: “请你不要开玩笑”。后面了解了来龙去脉,我才接受了这个我根本不想接受的事实。很多时候,我们都是通过新闻或者其他途径看到一系列诸如此类的新闻报道,感触可能只是一时的,但是我从未想过,这样的事情会发生在我自己的身边,所以我刚开始真的接受不了这个事实,我想我一辈子都忘不了。

好友生前是我的师弟,我是他刚上大学那会的助班,我们的人物关系是存在很多交集的,所以我很惋惜。在我心里他是一个积极向上、性格开朗、活泼、勤奋好学的学生,你平时跟他相处,完全不会感知到他竟然会是一个抑郁症患者,我们平时的交流中,他并没有向我表达过非常消极的态度,偶尔会跟我咨询一些专业上的问题,他在学业上以及专业上是有自己的规划的。我得知这个消息之后,我重新打开了我们的聊天记录,时间永远停留在了几个月前的那一天。那会的我们谈笑风生,还在讨论敲代码的事情,他还提醒我不要熬夜,我也跟他说以后过来我工作的地方直接找我玩。曾经诙谐的对话,如今却成了永恒。

“希望人人都没有疾病的困扰” ,这句话是他 Wechat 最后的个性签名。当我看到的时候,我突然觉得很心疼,他一定很痛苦,因为没人了解他内心的痛楚,逐渐的变得很压抑,最后抑郁。抑郁症患者心里有多痛苦,只有他们自己心里知道,但是我希望每个人不管遇到多大的疾病或者困难,都不应该放弃自己,要敢于战胜困难。很多抑郁症患者最终选择结束生命是因为不想连累或者拖累身边的家庭以及朋友,想自己一个人承担所有的痛苦,最后选择结束自己的生命 。我觉得应该要努力的活下去,这样才是为身边的所有人着想,你要知道,你的离开,身边的家人要承受一辈子的悲痛。没有什么难关是跨不过去的,很多人说我可能一辈子都买不了房,我可能没有未来?我也经常自言自语,想想现在的房价以及自己的家庭情况、工作情况等等,然后发问自己:日子什么时候是个头啊,哎,真的太难了。我们可以吐槽发生在自己的身边的事情,缓解压力,但是不能够自暴自弃,年纪轻轻就给了自己一张出局的牌。我自己的想法是:只要还活着就有希望,一家人平安喜乐,足矣。

原谅我的自言自语,最后,愿他在天堂的没有病痛的困扰,希望人人都没有疾病的困扰🌹

JavaScript纯原生的Base64编码加密解密封装代码片段

发表于 2019-10-17 | | 阅读次数:
字数统计: 457 | 阅读时长 ≈ 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
var Base64 = {

// private property
_keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

// public method for encoding
encode: function (input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;

input = Base64._utf8_encode(input);

while (i < input.length) {

chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);

enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;

if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}

output = output +
this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);

}

return output;
},

// public method for decoding
decode: function (input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;

input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

while (i < input.length) {

enc1 = this._keyStr.indexOf(input.charAt(i++));
enc2 = this._keyStr.indexOf(input.charAt(i++));
enc3 = this._keyStr.indexOf(input.charAt(i++));
enc4 = this._keyStr.indexOf(input.charAt(i++));

chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;

output = output + String.fromCharCode(chr1);

if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}

}

output = Base64._utf8_decode(output);

return output;

},

// private method for UTF-8 encoding
_utf8_encode: function (string) {
string = string.replace(/\r\n/g, "\n");
var utftext = "";

for (var n = 0; n < string.length; n++) {

var c = string.charCodeAt(n);

if (c < 128) {
utftext += String.fromCharCode(c);
} else if ((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}

}

return utftext;
},

// private method for UTF-8 decoding
_utf8_decode: function (utftext) {
var string = "";
var i = 0;
var c = c1 = c2 = 0;

while (i < utftext.length) {

c = utftext.charCodeAt(i);

if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if ((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i + 1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
} else {
c2 = utftext.charCodeAt(i + 1);
c3 = utftext.charCodeAt(i + 2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}

}

return string;
}
}
12…8
BinZhi Zhu

BinZhi Zhu

纵使你脚下有一千名挑战者,那就把我算作第一千零一名。

36 日志
4 分类
28 标签
RSS
0%
© 2020 BinZhi Zhu
Copyright © 2018
|
Powered by Hexo | Theme by Next
载入天数...载入时分秒...