携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第26天,点击查看活动详情
概述
一条查询 SQL 语句是如何执行的?
首先,数据是存储在 MySQL 服务端的。应用程序或者工具都是客户端。客户端要读写数据库,第一步要跟数据库建立连接。
通信协议
- 通信类型:同步或者异步
一般来说客户端连接数据库都是同步连接。
- 连接方式:长连接或者短连接
MySQL既支持短连接,也支持长连接。一般来说都是长连接,而且会把这个连接放到客户端的连接池。
可以用 show status 命令查看 MySQL 当前有多少个连接:
show global status like 'Thread%';
每产生一个连接或者一个会话,在服务端就会创建一个线程来处理。
| 字段 | 含义 |
|---|---|
| Threads_cached | 缓存中的线程连接数 |
| Threads_connected | 当前打开的连接数 |
| Threads_created | 为处理连接创建的线程数 |
| Threads_running | 非睡眠状态的连接数,通常指并发连接数 |
保持长连接会消耗内存。长时间不活动的连接,MySQL 服务器会断开。
show global variables like 'wait_timeout'; -- 非交互式超时时间,如 JDBC 程序
show global variables like 'interactive_timeout'; -- 交互式超时时间,如数据库工具
默认都是 28800 秒,8 小时。
MySQL 服务允许的最大连接数默认是 151 个,最大可以设置成 100000。
show variables like 'max_connections';
- 参数级别说明:
MySQL 中的参数分为 session 和 global 级别,分别是在当前会话中生效和全局生效,但是并不是每个参数都有两个级别,比如 max_connections 就只有全局级别。
当没有带参数的时候,默认是 session 级别,包括查询和修改。
比如修改了一个参数以后,在本窗口查询已经生效,但是其他窗口不生效:
show VARIABLES like 'autocommit';
set autocommit = on;
- 通信协议
在 Linux 服务器上,如果没有指定-h 参数,它就用 socket 方式登录。它不用通过网络协议,也可以连接到 MySQL 的服务器,它需要用到服务器上的一个物理文件 (/var/lib/mysql/mysql.sock)。
select @@socket;
如果指定-h 参数,就会用第二种方式,TCP/IP 协议。
mysql -h192.168.8.211 -uroot -p123456
编程语言的连接模块都是用TCP协议连接到MySQL服务器的,比如mysql-connector-java-x.x.xx.jar。
- 通信方式
- 单工:
在两台计算机通信的时候,数据的传输是单向的。生活中的类比:遥控器。
- 半双工:
在两台计算机之间,数据传输是双向的,你可以给我发送,我也可以给你发送,但是在这个通讯连接里面,同一时间只能有一台服务器在发送数据,也就是你要给我发的话,也必须等我发给你完了之后才能给我发。生活中的类比:对讲机。
- 全双工:
数据的传输是双向的,并且可以同时传输。生活中的类比:打电话。
总结
MySQL 使用了半双工的通信方式。
在一个连接中,要么是客户端向服务端发送数据,要么是服务端向客户端发送数据,这两个动作不能同时发生。所以客户端发送SQL语句给服务端的时候,(在一次连接里面)数据是不能分成小块发送的,不管你的SQL语句有多大,都是一次性发送。
比如用 MyBatis动态 SQL 生成了一个批量插入的语句,插入 10 万条数据,values后面跟了一长串的内容,或者 where 条件 in 里面的值太多,会出现问题。
这个时候必须要调整 MySQL 服务器配置 max_allowed_packet 参数的值(默认是4M),把它调大,否则就会报错。
另一方面,对于服务端来说,也是一次性发送所有的数据,不能因为你已经取到了想要的数据就中断操作,这个时候会对网络和内存产生大量消耗。
所以,在程序里面要避免不带 limit 的这种操作,比如一次把所有满足条件的数据全部查出来,一定要先 count 一下。如果数据量的话,可以分批查询。
因内容较长 因此分多篇进行讲解。未完待续。。。。。。