千家信息网

MYSQL sql执行过程的一些跟踪分析(一)

发表于:2025-11-07 作者:千家信息网编辑
千家信息网最后更新 2025年11月07日,与oracle或其他的数据库都差不多,一条sql的执行主要还是要经历了解析、优化、执行这几个过程,稍微具体下总结,MYSQL的主要过程如下: 客户端发起连接-----连接器,主要分配线程,验证权限--
千家信息网最后更新 2025年11月07日MYSQL sql执行过程的一些跟踪分析(一)与oracle或其他的数据库都差不多,一条sql的执行主要还是要经历了解析、优化、执行这几个过程,稍微具体下总结,MYSQL的主要过程如下: 客户端发起连接-----连接器,主要分配线程,验证权限----分析器,对sql语句语法进行分析-----优化器,生成准确的执行计划-----执行器,执行语句,发起读写数据,返回结果--之后对数据读写是io线程与存储引擎的交互 在客户端连接部分,涉及到TCP三次握手过程,我已在《MYSQL 连接登录过程分析》中尝试进行分析。 http://blog.itpub.net/29863023/viewspace-2216731/ 尝试用strace追踪mysqld进程,观察发起一个连接去执行sql时的情况:
[root@cwdtest1 ~]# strace -f -F -ff -o mysqld-strace -s 1024 -p 62509strace: Process 62509 attached with 32 threads....strace: Process 33059 attached
[root@cwdtest1 /]# mysql -uroot -pcwdrootmysql: [Warning] Using a password on the command line interface can be insecure.Welcome to the MySQL monitor.  Commands end with ; or \g.Your MySQL connection id is 24Server version: 5.7.23-23-log Source distributionCopyright (c) 2009-2018 Percona LLC and/or its affiliatesCopyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.Oracle is a registered trademark of Oracle Corporation and/or itsaffiliates. Other names may be trademarks of their respectiveowners.Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.mysql> select * from cwdtest.test;+---------+----------+| col1    | col2     |+---------+----------+|         | aaaaaaaa || ccccccc | NULL     |+---------+----------+2 rows in set (0.00 sec)mysql> exitBye

从performance_schema.threads中可以看到新增的54号前台线程thread/sql/one_connection,其os 线程id是33059

*************************** 31. row ***************************          THREAD_ID: 54               NAME: thread/sql/one_connection               TYPE: FOREGROUND     PROCESSLIST_ID: 28   PROCESSLIST_USER: root   PROCESSLIST_HOST: localhost     PROCESSLIST_DB: NULLPROCESSLIST_COMMAND: Sleep   PROCESSLIST_TIME: 10  PROCESSLIST_STATE: NULL   PROCESSLIST_INFO: NULL   PARENT_THREAD_ID: 1               ROLE: NULL       INSTRUMENTED: YES            HISTORY: YES    CONNECTION_TYPE: Socket       THREAD_OS_ID: 33059 《======31 rows in set (0.00 sec)
分析strace的过程信息: 获取线程id33059,之后设置 setsockopt状态。这里看到open /dev/urandom,这是获取一个随机编号
set_robust_list(0x7f9aa60ea9e0, 24) = 0gettid() = 33059setsockopt(67, SOL_TCP, TCP_NODELAY, [1], 4) = -1 EOPNOTSUPP (Operation not supported)setsockopt(67, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0open("/dev/urandom", O_RDONLY) = 68read(68, "'\275|\274\277\200Uw\2205\3)M\4E\364C\372\210\222\235\345\33I\216\252\206M\336C;\372", 32) = 32close(68) = 0

之后是密码验证,以及一些版本消息等

sendto(67, "Q\0\0\0\n5.7.23-23-log\0\34\0\0\0{PR&1|0 \0\377\367!\2\0\377\201\25\0\0\0\0\0\0\0\0\0\0\4\26:5.h\34U\"G%a\0mysql_native_password\0", 85, MSG_DONTWAIT, NULL, 0) = 85recvfrom(67, "\272\0\0\1", 4, MSG_DONTWAIT, NULL, NULL) = 4recvfrom(67, "\205\246\377\1\0\0\0\1!\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0root\0\24\v\10A\216\"\344i\31'\331UMa\"\356\4\3640!\331mysql_native_password\0i\3_os\5Linux\f_client_name\10libmysql\4_pid\00533058\17_client_version\t5.7.23-23\t_platform\6x86_64\fprogram_name\5mysql", 186, MSG_DONTWAIT, NULL, NULL) = 186sendto(67, "\7\0\0\2\0\0\0\2\0\0\0", 11, MSG_DONTWAIT, NULL, 0) = 11recvfrom(67, "!\0\0\0", 4, MSG_DONTWAIT, NULL, NULL) = 4recvfrom(67, "\3select @@version_comment limit 1", 33, MSG_DONTWAIT, NULL, NULL) = 33sendto(67, "\1\0\0\1\1'\0\0\2\3def\0\0\0\21@@version_comment\0\f!\0009\0\0\0\375\0\0\37\0\0\24\0\0\3\23Source distribution\7\0\0\4\376\0\0\2\0\0\0", 83, MSG_DONTWAIT, NULL, 0) = 83recvfrom(67, 0x7f9a9000a730, 4, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable)poll([{fd=67, events=POLLIN|POLLPRI}], 1, 28800000) = 1 ([{fd=67, revents=POLLIN}])

接受到shelect 的查询语句,我们可以看到 会stat ./cwdtest/test.frm 这个文件,这里是 获取文件信息,并在去访问./cwdtest/test.TRG,发现提示No such file or directory。

recvfrom(67, "\33\0\0\0", 4, MSG_DONTWAIT, NULL, NULL) = 4recvfrom(67, "\3select * from cwdtest.test", 27, MSG_DONTWAIT, NULL, NULL) = 27stat("./cwdtest/test.frm", {st_mode=S_IFREG|0640, st_size=8590, ...}) = 0access("./cwdtest/test.TRG", F_OK) = -1 ENOENT (No such file or directory)sendto(67, "\1\0\0\1\2-\0\0\2\3def\7cwdtest\4test\4test\4col1\4col1\f!\0\36\0\0\0\375\1\20\0\0\0-\0\0\3\3def\7cwdtest\4test\4test\4col2\4col2\f!\0\36\0\0\0\375\0\0\0\0\0\n\0\0\4\0\10aaaaaaaa\t\0\0\5\7ccccccc\373\7\0\0\6\376\0\0\"\0\0\0", 141, MSG_DONTWAIT, NULL, 0) = 141recvfrom(67, 0x7f9a9000a730, 4, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable)poll([{fd=67, events=POLLIN|POLLPRI}], 1, 28800000) = 1 ([{fd=67, revents=POLLIN|POLLHUP}])recvfrom(67, "\1\0\0\0", 4, MSG_DONTWAIT, NULL, NULL) = 4recvfrom(67, "\1", 1, MSG_DONTWAIT, NULL, NULL) = 1shutdown(67, SHUT_RDWR) = 0close(67) = 0futex(0x1dca184, FUTEX_WAIT_PRIVATE, 46, NULL (END)
来看看./cwdtest/test.frm 和 ./cwdtest/test.TRG两个文件:
frm是MySQL的表结构定义文件,通过hexdump可以查看其中16进制数据
[root@cwdtest1 cwdtest]# hexdump -C -v test.frm
00002130  20 20 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |                |00002140  20 20 20 20 20 20 20 20  20 20 20 20 20 20 20 00  |               .|00002150  04 00 05 63 6f 6c 31 00  05 00 05 63 6f 6c 32 00  |...col1....col2.|00002160  04 05 1e 1e 00 02 00 00  00 40 00 00 00 0f 21 00  |.........@....!.|00002170  00 05 05 1e 1e 00 21 00  00 00 80 00 00 00 0f 21  |......!........!|00002180  00 00 ff 63 6f 6c 31 ff  63 6f 6c 32 ff 00        |...col1.col2..|
以上列信息整理可得: 04 05 1e 1e 00 02 00 00 00 40 00 00 00 0f 21 00 00 --- 字段col1 05 05 1e 1e 00 21 00 00 00 80 00 00 00 0f 21 00 00-----字段col2 以col1字段为例: 其中04代表 列序号(初始列序号为4), 1e 表示字段长度,1e转化成十进制是30,表中是字是 varchar( 10 ),字符集是utf8占3bit,所以长度是10*3=30.
40表示不可为空,(DEFAULT NULL 80,NOT NULL 40,DEFAULT 'VALUE' 00)
0f表示字段类型是varhcar    21表示字符集是utf8
表创建语句:
| test | CREATE TABLE `test` (  `col1` varchar(10) NOT NULL,  `col2` varchar(10) DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
TRG文件是mysql中记录触发器的定义,很明显这里test表并没有创建触发器。
sendto(67, "\1\0\0\1\2-\0\0\2\3def\7cwdtest\4test\4test\4col1\4col1\f!\0\36\0\0\0\375\1\20\0\0\0-\0\0\3\3def\7cwdtest\4test\4test\4col2\4col2\f!\0\36\0\0\0\375\0\0\0\0\0\n\0\0\4\0\10aaaaaaaa\t\0\0\5\7ccccccc\373\7\0\0\6\376\0\0\"\0\0\0", 141, MSG_DONTWAIT, NULL, 0) = 141 之后便是调用sendto函数,往客户端发送结果。 当退出时便是关闭。 shutdown(67, SHUT_RDWR) = 0 close(67) = 0 在以上的trace日志里每个函数操作的对象基本都是67,67则是文件描述符,而这里对应的是socket。 [root@cwdtest1 fd]# ls -rtl 672 lrwx------ 1 root root 64 Jan 19 11:19 67 -> socket:[16206507]
文件 过程 分析 字段 线程 数据 语句 信息 客户 客户端 函数 字符 字符集 序号 结果 触发器 长度 尝试 验证 明显 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 4g移动网络安全风险场景 山西财智通软件开发有限公司 西安软件开发合伙人 江苏5g专业服务器机柜云空间 智能垃圾分类系统软件开发 社交软件分享功能数据库设计 桓台工具软件开发 网络安全技术岗位专业测试题 大专计算机网络技术都学什么 计算机客户服务器模式 360网页怎么不记录数据库 西安华为软件开发薪资待遇 url 服务器地址 网络安全坐标图片 网络安全快乐伴我成长手抄报 vue获取数据库图片路径 运维日常中经常往数据库中加表吗 运程管理服务器 医院网络安全培训通知模板 南昌高性能服务器 广东广电网络技术学院 嵌入式软件开发的技术原理 江苏5g专业服务器机柜云空间 如何调网易云游戏平台的服务器 企业资源管理系统数据库实训 向服务器发起一个http请求 内蒙古有网络技术有限公司 网络安全法25条的理解 北京惠普服务器虚拟化建设 南昌高性能服务器
0