本文是 MySQL 简单查询语句执行过程分析
6 篇中的第 5 篇,第 1 ~ 4 篇请看这里:
[1. 词法分析 & 语法分析]
[2. 查询准备阶段]
[3. 从 InnoDB 读数据]
[4. WHERE 条件]
经过前面几篇文章的讲述之后,终于来到了发送数据阶段,今天我们一起来看看 server 层读取到一条记录之后,发送给客户端之前都做了些什么?
对于 select 语句,MySQL 在执行过程中会把字段信息、数据记录发送给客户端,这两部分是分开发送的。完成查询优化
之后,从存储引擎读取第一条记录之前,会先把 select 语句中的字段信息
发送给客户端。然后从存储引擎读取记录,每读取一条记录,都会把该记录发送给客户端,然后再读取下一条记录并发送给客户端。
MySQL 发送字段信息和数据记录,根据发送内容的长度,有可能直接发送给客户端,也有可能是先写入网络缓冲区,等缓冲区满再一次性发送给客户端,本文中我们先不区分这两种不同的情况,都统一描述为
发送给客户端
。关于网络缓冲区,我们将在下一篇介绍。
接下来我们详细说说发送字段信息、数据记录这两部分内容。
示例表如下:
CREATE TABLE `t_recbuf` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`i1` int(10) unsigned DEFAULT '0',
`str1` varchar(32) DEFAULT '',
`str2` varchar(255) DEFAULT '',
`c1` char(11) DEFAULT '',
`e1` enum('北京','上海','广州','深圳','天津','杭州','成都','重庆','苏州','南京','哈尔滨','沈阳','长春','厦门','福州','南昌','泉州','德清','长沙','武汉') DEFAULT '北京',
`s1` set('吃','喝','玩','乐','衣','食','住','行','前后','左右','上下','里外','远近','长短','黑白','水星','金星','地球','火星','木星','土星','天王星','海王星','冥王星') DEFAULT '',
`bit1` bit(8) DEFAULT b'0',
`bit2` bit(17) DEFAULT b'0',
`blob1` blob,
`d1` decimal(10,2) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2001 DEFAULT CHARSET=utf8;
MySQL 只会把客户端需要的那些字段的字段信息发送给它,那么,MySQL 怎么知道要发送哪些字段的字段信息呢?
这个对于 MySQL 来说是小意思,select 中指定的字段,保存在一个叫 fields
的属性里,发送字段信息时,会遍历这个属性中的每一个字段,把字段信息发送给客户端。
开始发送字段信息之前,会先把字段数量
发送给客户端。
然后把每个字段的以下信息发送给客户端:
字段定义
)字段信息发送完成之后,会发送结束包
给客户端,长度 5 字节,表示的是服务器的状态。
MySQL 发送数据记录时,也只会发送客户端需要的那些字段的内容。依然要用到那个叫 fields
的属性,遍历 fields 中的每个字段,把字段的内容转换为字符串
,以及进行一些必要的逻辑处理之后,发送给客户端。
接下来,我们就来看看示例表中每种类型的字段怎么转换为字符串,以及还有可能涉及到哪些逻辑要处理?
id、i1 字段都是 int 类型,字段值会由整数转换为字符串,因为指定了是无符号整数(unsigned
),转换为字符串之后,数字前面不会有符号(+、- 都不会有)。
如果建表时,int 字段指定了 zerofill
,把整数转换为字符串之后,会在前面用 0
把字符串填充到指定长度,如 id 定义为 int(10), 假设字段值为 24,转换为字符串之后,会在前面补充 10 - 2 = 8 个 0,变成 0000000024
。
经过把整数转换为字符串,以及可能需要操作的在字符串前面补充 0
之后,内容就准备就绪了,然后把字符串长度
和内容
发送给客户端。
str1、str2 字段都是 varchar 类型,本身就是字符串,不需要转换。str1 和 str2 唯一区别就是 str1 用 1 字节存储内容长度,str2 用 2 字节存储内容长度。
发送数据前,只需要先读取字段内容的长度
(字节数),再读取相应字节数的内容,然后把长度
和内容
发送给客户端。
c1 字段是 char 类型,本身就是字符串,不需要转换。
char 类型字段,取决于 sql_mode 是否开启了 PAD_CHAR_TO_FULL_LENGTH
选项,发送给客户端的内容会有些差别。
c1 字段的定义是 char(11),我们以 c1 字段的内容 24 测试char
为例来说明。
如果开启了 PAD_CHAR_TO_FULL_LENGTH
选项,字符串内容后面会填充相应数量的空格,使内容中的字符数达到字段定义时的数量,24 测试char
有 9 个字符,会在后面填充 11 - 9 = 2 个空格,变成 24 测试char__
,注意:2 个下划线代表 2 个空格。
如果 sql_mode 没有开启 PAD_CHAR_TO_FULL_LENGTH
选项,字符串内容后面不会有空格,就是这样的了:24 测试char
,注意:最后没有空格。
上面处理完成后,就可以愉快的把字段内容长度
和字段内容
发送给客户端了。
enum 类型字段,在存储引擎中以整数存储,发送数据之前,会找到整数对应选项的内容作为字段内容
,如果没有找到对应的选项,字段内容就是:空字符串
。
示例表中 e1 字段各选项及其对应的整数值如下图:
假设存储引擎返回的 e1 字段整数值为 7
,发送数据之前,会找到 7 对应选项的内容成都
,占用字节数为 2(字数)* 3(utf8 一个汉字占用字节数)= 6 字节,把内容长度 6
和内容成都
发送给客户端。
set 类型字段,在存储引擎中也是以整数存储,发送数据之前,通过整数找到一个或多个对应选项的内容作为字段内容
,如果有多个选项,字段内容中多个选项的内容之间用逗号分隔。
示例表中 s1 字段定义时指定的选项为:吃, 喝, 玩, 乐, 衣, 食, 住, 行, 前后, 左右, 上下, 里外, 远近, 长短, 黑白, 水星, 金星, 地球, 火星, 木星, 土星, 天王星, 海王星, 冥王星,共 24 个选项,每个选项占用 1 bit。
假设存储引擎返回的 s1 字段整数值为 2163720
,遍历 s1 字段的 24 个选项,判断 2163720 中每一个选项对应的 bit 是否为 1
,如果为 1,则把该选项内容(如天王星
)追加到 s1 字符串值的后面,用逗号分隔,最终会得到字段内容乐,上下,金星,天王星
,然后把字段内容长度 27
和字段内容乐,上下,金星,天王星
发送给客户端。
一个汉字占 3 字节,一个逗号(,)占 1 字节。
为什么 2163720 转换为字符串是乐,上下,金星,天王星
?
乐
是第 4 个选项,序号为 3,值为 1 << 3 = 8。上下
是第 11 个选项,序号为 10,值为 1 << 10 = 1024。金星
是第 17 个选项,序号为 16,值为 1 << 16 = 65536。天王星
是第 22 个选项,序号为 21,值为 1 << 21 = 2097152。2163720 由 4 个选项按位或
计算得到:8 | 1024 | 65536 | 2097152 = 2163720,二进制示意图如下:
bit 类型字段,发送数据前,也要转换为字符串,就是我们熟悉的那种只包含 0 和 1 的二进制内容。
bit 类型字段在 InnoDB 中是以 C/C++ 中的 char 类型存储的,实际就是按字节存储,1 字节可以存储 8 bit,示例表结构中,bit1 定义为 bit(8) 正好占用 1 字节,bit2 定义为 bit(17),用 2 字节不够存,多出来 1 bit 也需要占用 1 字节,所以需要 3 字节来存储。
存储引擎返回 bit 类型字段给 server 层时,就是以 C/C++ 中的 char *
指针返回的。
例如,某条记录的 bit1 字段值转换为字符串 00010001
,长度为 8 字节,把长度 8
和内容 00010001
发送给客户端。bit2 字段值转换为字符串 00000000000011111
,长度为 17 字节,把长度 17
和内容 00000000000011111
发送给客户端。
blob 类型字段,本身就是字符串,不需要转换。
blob 类型字段有个和其它字段不一样的地方,存储引擎返回记录给 server 层时,并没有把 blob 字段内容写入记录缓冲区
,而是在引擎层分配了一块内存用于存储 blob 字段内容,并把内容的内存首地址
写入记录缓冲区,发送数据时,根据内容的内存首地址
直接从引擎层存储 blob 字段内容的内存区域中读取字段内容,把字段容内容长度
和字段内容
发送给客户端。
关于 server 层和引擎层交换内容的
记录缓冲区
,可以参考这篇文章:[MySQL server 层和存储引擎层是怎么交互数据的?]
decimal 类型在存储引擎中是以二进制存储的,发送数据之前,会先把二进制转换为浮点数,然后再把浮点数转换为字符串,把字符串内容长度
和字符串内容
发送给客户端。
以上,就是本文的全部内容了,感谢大家花时间阅读,如果觉得有用,还请帮忙转发朋友圈,让更多的人看到,大家一起进步,谢谢 ^_^
预告一下,下一篇要写的内容是 MySQL 简单查询语句执行过程分析(六)网络缓冲区
,敬请关注!
本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/dJD3bWaAI8T78-phVBuo3A
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。