千家信息网

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

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,与oracle或其他的数据库都差不多,一条sql的执行主要还是要经历了解析、优化、执行这几个过程,稍微具体下总结,MYSQL的主要过程如下: 客户端发起连接-----连接器,主要分配线程,验证权限--
千家信息网最后更新 2026年11月01日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安全错误 数据库的锁怎样保障安全 中智农互联网科技 上海互联网科技有限公司 睿民互联网科技 互联网 新科技 上海卓越科技 互联网 国外互联网科技网站 左右互联网络科技 哈尔滨新华互联网科技 互联网巨头投资的硬核科技 中国科技互联网公司收入 南山科技园互联网公司有哪些 崇明区互联网教育科技诚信经营 杭州壁岐互联网科技有限公司 互联网行业科技股 无锡工业互联网科技有限公司 广州富喜互联网络科技 四川互联网展示科技馆设计 福建互联网展示科技馆设计 互联网科技创业有什么好项目 科技发展第三阶段互联网时代 河南云网互联网络科技有限公司 多迪互联网科技有限公司 银川新华互联网科技学校地址 科技赋能互联网健康 重庆威客帮互联网科技 互联网科技项目计划书材料类 智腾互联网科技有限公司 富国互联网科技002692 信承诺互联网科技有限公司 互联网的黑科技实验室
0