从源码编译的mysql服务器,带debug信息,已安装gdb,便于学习和调试mysql功能及源码。
> wget https://raw.githubusercontent.com/leo18945/docker-mysql-debug/master/docker-compose.yml
> docker-compose up -d
> docker exec -it mysql-debug bash
root@1d1e15b4c637:/work#
root@1d1e15b4c637:/work# cat /etc/*release
PRETTY_NAME="Debian GNU/Linux 10 (buster)"
NAME="Debian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
wget https://cdn.mysql.com/archives/mysql-5.7/mysql-boost-5.7.29.tar.gz
cmake \
-DCMAKE_INSTALL_PREFIX=/work/mysql \
-DMYSQL_DATADIR=/work/mysql/data \
-DMYSQL_UNIX_ADDR=/work/mysql/tmp/mysql.sock \
-DDEFAULT_CHARSET=utf8mb4 \
-DDEFAULT_COLLATION=utf8mb4_unicode_ci \
-DEXTRA_CHARSETS=all \
-DENABLED_LOCAL_INFILE=1 \
-DDOWNLOAD_BOOST=0 \
-DWITH_BOOST=/work/mysql-5.7.29/boost/boost_1_59_0 \
-DWITH_DEBUG=1 \
-DWITH_EMBEDDED_SERVER=0 \
-DWITH_EMBEDDED_SHARED_LIBRARY=0
root@9d80e46284e8:/work# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 996 4 ? Ss 19:45 0:00 /sbin/docker-init -- /work/docker-entrypoint.sh
root 8 0.0 0.0 5488 3104 ? S 19:45 0:00 /bin/bash /work/docker-entrypoint.sh
mysql 36 0.2 4.9 2186544 211876 ? Sl 19:45 0:00 mysqld --defaults-file=/work/my.cnf --debug --user=mysql
root 64 0.0 0.0 5752 3640 pts/0 Ss 19:45 0:00 bash
root 82 0.0 0.0 9392 3064 pts/0 R+ 19:49 0:00 ps aux
root@9d80e46284e8:/work# envs
BASH_ALIAS=/etc/bash.bashrc; alias ll='ls -laFh'; alias lls='ll -S'
BCVIEW_COMMAND=bcview table.ibd 16 94 200
BITNAMI_IMAGE_VERSION=mysql-version: 5.7.29
GDB_BREAKPOINT=gdb breakpoint handle_query do_select do_command JOIN::exec JOIN::get_end_select_func st_select_lex_unit::execute st_select_lex_unit::set_limit st_select_lex_unit::cleanup st_select_lex_unit::first_select Materialized_cursor::send_result_set_metadata JOIN::make_join_plan Optimize_table_order::choose_table_order Optimize_table_order::greedy_search
GDB_COMMAND=gdb -p <mysqld-pid> -ex 'p dict_sys->row_id=281474976710656' -batch
HOME=/
GDB_LOAD_BREAKPOINT=source /work/mysql-breakpoints.txt
HOSTNAME=9d80e46284e8
INNBLOCK_COMMAND=innblock table.ibd scan 16
MYSQL_CHANGE_PASSWORD=set password = password('pass');
MYSQL_CONF_FILE=/etc/my.cnf
MYSQL_DATA_DIR=/work/mysql/data
MYSQL_GREP_ROOT_PASSWORD=grep 'temporary password' /work/mysql/log/mysqld.log
MYSQL_HOME=/work/mysql
MYSQL_SOURCE_DIR=/work/mysql-5.7.29
MYSQL_PAGE_COPY_COMMAND=dd if=table.ibd of=new.hex skip=4 bs=16k count=1
MYSQL_START_CLIENT=mysql -u root -p
OS_ARCH=amd64
OS_FLAVOUR=debian-10
OS_NAME=linux
PATH=/work/mysql/bin:/work:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/work
SHLVL=1
TERM=xterm
_=/usr/bin/env
> cat /etc/my.cnf
[mysqld]
# 不解析客户端主机名,这样就只能在mysql的授权表中对客户端IP授权,不能对主机名授权
skip_name_resolve = true
bind_address = 0.0.0.0
port = 3306
max_allowed_packet = 16M
explicit_defaults_for_timestamp = 1
# 1-表名等全转为小写存储,查询等也转为小写对比
lower_case_table_names = 1
#############################################################
# 设置mysql运行的各级目录
basedir = /work/mysql
datadir = /work/mysql/data
tmpdir = /work/mysql/tmp
pid_file = /work/mysql/tmp/mysqld.pid
socket = /work/mysql/tmp/mysql.sock
#############################################################
# 数据库默认字符集,utf8mb4符集支持表情符号(表情符号占4个字节)
character_set_server = utf8mb4
collation_server = utf8mb4_unicode_ci
# 是否允许客户端设置会话的字符集,此处允许
# skip-character-set-client-handshake = off
character-set-client-handshake = on
# init_connect = 'SET NAMES utf8mb4'
#############################################################
# The locale to use for error messages. The default is en_US.
# lc_messages_dir = /work/mysql/share
lc_messages = en_US
#############################################################
# 开启系统日志
log_error = /work/mysql/log/mysqld.log
# 开启查询日志
general_log = on
general_log_file = /work/mysql/log/general.log
# 开启慢查询日志功能
# slow_query_log = on
# slow_query_log_file = /work/mysql/log/slow_query.log
# 查询超过多长时间的SQL才会记录到慢查询日志文件(默认时间为10秒)
# long_query_time = 10
# log_queries_not_using_indexes = on
#############################################################
# 用来限制LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE()传到哪个指定目录的,或者system ls /可以访问哪个目录
secure_file_priv = /
# 设置mysql服务器id,为了在使用binlog功能时区分不同的服务器
server-id = 1
# 开启binlog,并设置log_bin_index前缀为mysql-bin
log_bin = mysql-bin
# 是否信任创建存储过程的创建者,信任他们在创建存储过程时不会修改库中表的数据,否则容易导致主从复制时数据不一致,此处信任
log_bin_trust_function_creators = on
[client]
port = 3306
socket = /work/mysql/tmp/mysql.sock
default_character_set = utf8mb4
[mysql]
default-character-set = utf8mb4
socket = /work/mysql/tmp/mysql.sock
# https://gist.github.com/rhtyd/d59078be4dc88123104e
# https://fromdual.com/mysql-configuration-file-sample
root@9d80e46284e8:/work# grep 'temporary password' /work/mysql/log/mysqld.log
2021-02-23T12:41:00.778375Z 1 [Note] A temporary password is generated for root@localhost: sfUr7ha2qg,5
root@9d80e46284e8:/work# mysql -u root -p
Enter password: sfUr7ha2qg,5
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.29-debug
mysql> set password = password('pass');
mysql> create database test;
mysql> use test;
mysql> create table test1(name varchar(20));
mysql> insert into test1 values('AAA');
mysql> select * from test1;
+------+
| name |
+------+
| AAA |
+------+
mysql> create table test2(name varchar(20));
mysql> insert into test2 values('BBB');
mysql> select * from test2;
+------+
| name |
+------+
| BBB |
+------+
mysql> system bcview /work/mysql/data/test/test1.ibd 16 94 100
current block:00000003--Offset:00094--cnt bytes:100--data is:010002001c696e66696d756d0002000b000073757072656d756d0300000010fff1000000000200000000000507a70000011b0110414141000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
# block:00000003字节码分析如下
rcd_header row_id trx_id ptr_id name
03 00 000010fff1 000000000200 000000000507 a70000011b0110 414141
mysql> select conv('200', 16, 10);
+---------------------+
| conv('200', 16, 10) |
+---------------------+
| 512 |
+---------------------+
# 可以看出,rowid从512开始
mysql> system bcview /work/mysql/data/test/test2.ibd 16 94 100
current block:00000003--Offset:00094--cnt bytes:100--data is:010002001c696e66696d756d0002000b000073757072656d756d0300000010fff100000000020100000000050cac000001200110424242000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
# block:00000003字节码分析如下
rcd_header row_id trx_id ptr_id name
03 00 000010fff1 000000000201 00000000050c ac000001200110 424242
mysql> select conv('201', 16, 10);
+---------------------+
| conv('201', 16, 10) |
+---------------------+
| 513 |
+---------------------+
# 可以看出,rowid从513开始
# 多个表共用一个dict_sys.row_id变量值
# 查看使用gdb修改mysql rowid的命令
mysql> system echo $GDB_COMMAND
gdb -p <mysqld-pid> -ex 'p dict_sys->row_id=281474976710656' -batch
# 使用ps查看mysqld的进程ID
mysql> system ps aux | grep 3306
mysql 297 0.1 5.1 2186352 221700 pts/0 Sl 13:07 0:01 /work/mysql/bin/mysqld --basedir=/work/mysql --datadir=/work/mysql/data --plugin-dir=/work/mysql/lib/plugin --user=mysql --log-error=/work/mysql/log/mysqld.log --pid-file=/work/mysql/data/cb76697ed1bf.pid --socket=/work/mysql/tmp/mysql.sock --port=3306
root 371 0.0 0.0 2388 692 pts/0 S+ 13:22 0:00 sh -c ps aux | grep 3306
root 373 0.0 0.0 3084 888 pts/0 S+ 13:22 0:00 grep 3306
# 执行gdb命令修改mysql dict_sys->row_id 的值为10000
# 即没主键的表插入数据时从dict_sys->row_id处取值
mysql> system gdb -p 297 -ex 'p dict_sys->row_id=10000' -batch
[New LWP 298]
...
[New LWP 346]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
0x00007f4b561e2819 in __GI___poll (fds=0x556d880cabd0, nfds=2, timeout=-1) at ../sysdeps/unix/sysv/linux/poll.c:29
29 ../sysdeps/unix/sysv/linux/poll.c: No such file or directory.
$1 = 10000
[Inferior 1 (process 297) detached]
# 再向test1表中插入数据,看新的rowid是多少
mysql> insert into test1 values('CCC');
Query OK, 1 row affected (0.00 sec)
mysql> insert into test2 values('DDD');
Query OK, 1 row affected (0.00 sec)
# 读取test1表中page3的字节码分析
mysql> system bcview /work/mysql/data/test/test1.ibd 16 94 100
current block:00000003--Offset:00094--cnt bytes:100--data is:010002001c696e66696d756d0003000b000073757072656d756d0300000010001d000000000200000000000507a70000011b01104141410300000018ffd400000000271000000000050dad00000121011043434300000000000000000000000000000000
# block:00000003字节码分析如下
rcd_header row_id trx_id ptr_id name
03 00 000010001d 000000000200 000000000507 a70000011b0110 414141
03 00 000018ffd4 000000002710 00000000050d ad000001210110 434343
mysql> select conv('2710', 16, 10);
+----------------------+
| conv('2710', 16, 10) |
+----------------------+
| 10000 |
+----------------------+
# test1 表已使用新的 rowid
mysql> system bcview /work/mysql/data/test/test2.ibd 16 94 100
current block:00000003--Offset:00094--cnt bytes:100--data is:010002001c696e66696d756d0003000b000073757072656d756d0300000010001d00000000020100000000050cac0000012001104242420300000018ffd4000000002711000000000512b000000124011044444400000000000000000000000000000000
# block:00000003字节码分析如下
rcd_header row_id trx_id ptr_id name
03 00 000010001d 000000000201 00000000050c ac000001200110 424242
03 00 000018ffd4 000000002711 000000000512 b0000001240110 444444
mysql> select conv('2711', 16, 10);
+----------------------+
| conv('2711', 16, 10) |
+----------------------+
| 10001 |
+----------------------+
# test2 表已使用新的 rowid
CREATE TABLE emp (
empno decimal(4,0) NOT NULL,
ename varchar(10),
job varchar(9),
mgr decimal(4,0),
hiredate date,
sal decimal(7,2),
comm decimal(7,2),
deptno decimal(2,0)
);
CREATE TABLE dept (
deptno decimal(2,0),
dname varchar(14),
loc varchar(13)
);
INSERT INTO emp VALUES
('7369','SMITH','CLERK','7902','1980-12-17','800.00',NULL,'20'),
('7499','ALLEN','SALESMAN','7698','1981-02-20','1600.00','300.00','30'),
('7521','WARD','SALESMAN','7698','1981-02-22','1250.00','500.00','30'),
('7566','JONES','MANAGER','7839','1981-04-02','2975.00',NULL,'20'),
('7654','MARTIN','SALESMAN','7698','1981-09-28','1250.00','1400.00','30'),
('7698','BLAKE','MANAGER','7839','1981-05-01','2850.00',NULL,'30'),
('7782','CLARK','MANAGER','7839','1981-06-09','2450.00',NULL,'10'),
('7788','SCOTT','ANALYST','7566','1982-12-09','3000.00',NULL,'20'),
('7839','KING','PRESIDENT',NULL,'1981-11-17','5000.00',NULL,'10'),
('7844','TURNER','SALESMAN','7698','1981-09-08','1500.00','0.00','30'),
('7876','ADAMS','CLERK','7788','1983-01-12','1100.00',NULL,'20'),
('7900','JAMES','CLERK','7698','1981-12-03','950.00',NULL,'30'),
('7902','FORD','ANALYST','7566','1981-12-03','3000.00',NULL,'20'),
('7934','MILLER','CLERK','7782','1982-01-23','1300.00',NULL,'10');
INSERT INTO dept VALUES
('10','ACCOUNTING','NEW YORK'),
('20','RESEARCH','DALLAS'),
('30','SALES','CHICAGO'),
('40','OPERATIONS','BOSTON');
# 启动 gdb
root@1d1e15b4c637:/work/mysql# gdb
GNU gdb (Debian 8.2.1-2+b3) 8.2.1
Type "apropos word" to search for commands related to "word".
# attch 进 mysqld 进程
(gdb) attach 1400
Attaching to process 1400
[New LWP 1401]
...
[New LWP 1430]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
0x00007eff45352819 in __GI___poll (fds=0x55582c637fe0, nfds=2, timeout=-1) at ../sysdeps/unix/sysv/linux/poll.c:29
29 ../sysdeps/unix/sysv/linux/poll.c: No such file or directory.
(gdb) source /work/mysql-breakpoints.txt
Breakpoint 1 at 0x564cacb3121f: file /work/mysql-5.7.29/sql/sql_select.cc, line 107.
Breakpoint 2 at 0x564caca9be4b: file /work/mysql-5.7.29/sql/sql_executor.cc, line 885.
Breakpoint 3 at 0x564cacadca77: file /work/mysql-5.7.29/sql/sql_parse.cc, line 907.
Breakpoint 4 at 0x564caca99b6b: file /work/mysql-5.7.29/sql/sql_executor.cc, line 106.
Breakpoint 5 at 0x564cacac7045: file /work/mysql-5.7.29/sql/sql_optimizer.cc, line 5021.
Breakpoint 6 at 0x564cacb007bb: file /work/mysql-5.7.29/sql/sql_planner.cc, line 1832.
Breakpoint 7 at 0x564cacb0133b: file /work/mysql-5.7.29/sql/sql_planner.cc, line 2216.
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000564cacb3121f in handle_query(THD*, LEX*, Query_result*, unsigned long long, unsigned long long) at /work/mysql-5.7.29/sql/sql_select.cc:107
2 breakpoint keep y 0x0000564caca9be4b in do_select(JOIN*) at /work/mysql-5.7.29/sql/sql_executor.cc:885
3 breakpoint keep y 0x0000564cacadca77 in do_command(THD*) at /work/mysql-5.7.29/sql/sql_parse.cc:907
4 breakpoint keep y 0x0000564caca99b6b in JOIN::exec() at /work/mysql-5.7.29/sql/sql_executor.cc:106
5 breakpoint keep y 0x0000564cacac7045 in JOIN::make_join_plan() at /work/mysql-5.7.29/sql/sql_optimizer.cc:5021
6 breakpoint keep y 0x0000564cacb007bb in Optimize_table_order::choose_table_order() at /work/mysql-5.7.29/sql/sql_planner.cc:1832
7 breakpoint keep y 0x0000564cacb0133b in Optimize_table_order::greedy_search(unsigned long long) at /work/mysql-5.7.29/sql/sql_planner.cc:2216
(gdb) b handle_query
Breakpoint 1 at 0x564cacb3121f: file /work/mysql-5.7.29/sql/sql_select.cc, line 107.
(gdb) b do_select
Breakpoint 2 at 0x564caca9be4b: file /work/mysql-5.7.29/sql/sql_executor.cc, line 885.
(gdb) b do_command
Breakpoint 3 at 0x564cacadca77: file /work/mysql-5.7.29/sql/sql_parse.cc, line 907.
(gdb) b JOIN::exec
Breakpoint 4 at 0x564caca99b6b: file /work/mysql-5.7.29/sql/sql_executor.cc, line 106.
(gdb) b JOIN::make_join_plan
Breakpoint 5 at 0x564cacac7045: file /work/mysql-5.7.29/sql/sql_optimizer.cc, line 5021.
(gdb) b Optimize_table_order::choose_table_order
Breakpoint 6 at 0x564cacb007bb: file /work/mysql-5.7.29/sql/sql_planner.cc, line 1832.
(gdb) b Optimize_table_order::greedy_search
Breakpoint 7 at 0x564cacb0133b: file /work/mysql-5.7.29/sql/sql_planner.cc, line 2216.
(gdb) save breakpoints /work/mysql-breakpoints.txt
Saved to file '/work/mysql-breakpoints.txt'.
mysql> select a.empno, a.ename, b.dname, a.job, a.mgr, a.hiredate, a.sal, a.comm from emp a join dept b on b.deptno = a.deptno;
# 此处查询挂起,等待gdb执行
(gdb) c
Continuing.
Thread 28 "mysqld" hit Breakpoint 1, handle_query (thd=0x7fac3c000dd0, lex=0x7fac3c0030f0, result=0x7fac3c958248, added_options=0, removed_options=0)
at /work/mysql-5.7.29/sql/sql_select.cc:107
107 DBUG_ENTER("handle_query");
(gdb) c
Continuing.
Thread 28 "mysqld" hit Breakpoint 5, JOIN::make_join_plan (this=0x7fac3c958fe0) at /work/mysql-5.7.29/sql/sql_optimizer.cc:5021
5021 DBUG_ENTER("JOIN::make_join_plan");
(gdb) c
Continuing.
Thread 28 "mysqld" hit Breakpoint 6, Optimize_table_order::choose_table_order (this=0x7facb0040f70) at /work/mysql-5.7.29/sql/sql_planner.cc:1832
1832 DBUG_ENTER("Optimize_table_order::choose_table_order");
(gdb) c
Continuing.
Thread 28 "mysqld" hit Breakpoint 7, Optimize_table_order::greedy_search (this=0x7facb0040f70, remaining_tables=3) at /work/mysql-5.7.29/sql/sql_planner.cc:2216
2216 uint idx= join->const_tables; // index into 'join->best_ref'
# 打印调用栈
(gdb) bt
#0 Optimize_table_order::greedy_search (this=0x7facb0040f70, remaining_tables=3) at /work/mysql-5.7.29/sql/sql_planner.cc:2216
#1 0x0000564cacb00c69 in Optimize_table_order::choose_table_order (this=0x7facb0040f70) at /work/mysql-5.7.29/sql/sql_planner.cc:1910
#2 0x0000564cacac7431 in JOIN::make_join_plan (this=0x7fac3c958fe0) at /work/mysql-5.7.29/sql/sql_optimizer.cc:5091
#3 0x0000564cacabbe29 in JOIN::optimize (this=0x7fac3c958fe0) at /work/mysql-5.7.29/sql/sql_optimizer.cc:375
#4 0x0000564cacb32d70 in st_select_lex::optimize (this=0x7fac3c005be0, thd=0x7fac3c000dd0) at /work/mysql-5.7.29/sql/sql_select.cc:1016
#5 0x0000564cacb314f6 in handle_query (thd=0x7fac3c000dd0, lex=0x7fac3c0030f0, result=0x7fac3c958248, added_options=0, removed_options=0)
at /work/mysql-5.7.29/sql/sql_select.cc:171
#6 0x0000564cacae791b in execute_sqlcom_select (thd=0x7fac3c000dd0, all_tables=0x7fac3c956bf0) at /work/mysql-5.7.29/sql/sql_parse.cc:5155
#7 0x0000564cacae10f1 in mysql_execute_command (thd=0x7fac3c000dd0, first_level=true) at /work/mysql-5.7.29/sql/sql_parse.cc:2826
#8 0x0000564cacae8829 in mysql_parse (thd=0x7fac3c000dd0, parser_state=0x7facb0042650) at /work/mysql-5.7.29/sql/sql_parse.cc:5584
#9 0x0000564cacade006 in dispatch_command (thd=0x7fac3c000dd0, com_data=0x7facb0042df0, command=COM_QUERY) at /work/mysql-5.7.29/sql/sql_parse.cc:1491
#10 0x0000564cacadcf22 in do_command (thd=0x7fac3c000dd0) at /work/mysql-5.7.29/sql/sql_parse.cc:1032
#11 0x0000564cacc0c241 in handle_connection (arg=0x564caf501a00) at /work/mysql-5.7.29/sql/conn_handler/connection_handler_per_thread.cc:313
#12 0x0000564cad28e598 in pfs_spawn_thread (arg=0x564caf2c4d50) at /work/mysql-5.7.29/storage/perfschema/pfs.cc:2197
#13 0x00007facbd318fa3 in start_thread (arg=<optimized out>) at pthread_create.c:486
#14 0x00007facbcb584cf in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
# 查看源码
(gdb) list
2211 @return false if successful, true if error
2212 */
2213
2214 bool Optimize_table_order::greedy_search(table_map remaining_tables)
2215 {
2216 uint idx= join->const_tables; // index into 'join->best_ref'
2217 uint best_idx;
2218 POSITION best_pos;
2219 JOIN_TAB *best_table; // the next plan node to be added to the curr QEP
2220 DBUG_ENTER("Optimize_table_order::greedy_search");
(gdb) c
Continuing.
Thread 28 "mysqld" hit Breakpoint 4, JOIN::exec (this=0x7fac3c958fe0) at /work/mysql-5.7.29/sql/sql_executor.cc:106
106 Opt_trace_context * const trace= &thd->opt_trace;
(gdb) c
Continuing.
Thread 28 "mysqld" hit Breakpoint 2, do_select (join=0x7fac3c958fe0) at /work/mysql-5.7.29/sql/sql_executor.cc:885
885 int rc= 0;
(gdb) c
Continuing.
Thread 28 "mysqld" hit Breakpoint 3, do_command (thd=0x7fac3c000dd0) at /work/mysql-5.7.29/sql/sql_parse.cc:907
907 (thd->get_protocol()->type() == Protocol::PROTOCOL_TEXT ||
(gdb) c
Continuing.
mysql> select a.empno, a.ename, b.dname, a.job, a.mgr, a.hiredate, a.sal, a.comm from emp a join dept b on b.deptno = a.deptno;
+-------+--------+------------+-----------+------+------------+---------+---------+
| empno | ename | dname | job | mgr | hiredate | sal | comm |
+-------+--------+------------+-----------+------+------------+---------+---------+
| 7369 | SMITH | RESEARCH | CLERK | 7902 | 1980-12-17 | 800.00 | NULL |
| 7499 | ALLEN | SALES | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 |
| 7521 | WARD | SALES | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 |
| 7566 | JONES | RESEARCH | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL |
| 7654 | MARTIN | SALES | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 |
| 7698 | BLAKE | SALES | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL |
| 7782 | CLARK | ACCOUNTING | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL |
| 7788 | SCOTT | RESEARCH | ANALYST | 7566 | 1982-12-09 | 3000.00 | NULL |
| 7839 | KING | ACCOUNTING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL |
| 7844 | TURNER | SALES | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 |
| 7876 | ADAMS | RESEARCH | CLERK | 7788 | 1983-01-12 | 1100.00 | NULL |
| 7900 | JAMES | SALES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL |
| 7902 | FORD | RESEARCH | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL |
| 7934 | MILLER | ACCOUNTING | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL |
+-------+--------+------------+-----------+------+------------+---------+---------+
14 rows in set (9 min 44.61 sec)
Mysql优化器源码
https://blog.csdn.net/huoyuanshen/article/details/50420315
MySQL确定JOIN表顺序
https://zhuanlan.zhihu.com/p/102655586