计算机上可以运行多个程序,比如QQ,微信,idea,每个程序就是一个进程(PID),mysql服务器和客户端本质就是一个进程,进程都有id,简称PID。
我们都知道通过mysql -h localhost -u root -p 来启动客户端(-h代表需要连接的主机,-u代表用户名称,-p代表需要输入的密码)。
前面说了客户端和服务端本质都是进程,所以当他们交互的时候,本质上就是进程之间的通信。客户端与服务端的连接方式有多种,当使用localhost连接时候,mysql采用的是unix域套接字文件。当使用127.0.0.1会少解析一次,采用TPC/IP进行连接。
Mysql不管用什么方式连接,都会创建一个线程来专门管理客户端的交互,但当断开连接的时候,并不会把这个线程销毁,而是缓存起来,给另一个新的客户端使用,从而避免不必要的创建与销毁的开销。
连接后会解析与优化,分为查询缓存,语法解析,sql优化,存储引擎。
比如我们每次查询相同的数据,肯定会从缓存里查询,mysql也是如此,当sql语句完全相同的时候,会直接击中缓存返回给客户端,而且所有客户端是共享同一个缓存的,但也有缓存失效的时候,比如查询系统表的时候information_schema,当大小写不一致以及多了空格也不会击中缓存,当使用聚合函数的时候,也会放弃,比如now()。
当缓存里查询不到数据的时候,这时候就到了语法解析,会把客户端发送过来的文本解析成mysql可以读取的数据。之后会用查询优化,比如外连接转内连接,表达式简化,子查询等一些,生成一个执行计划,执行计划可以知道可能使用哪些索引,和实际使用哪些索引,以及查询计划,我们可以使用explain来查看执行计划。
后面就开始到存储引擎,这时候才真正访问数据库表。我们都知道表数据是一行一行的,但这只是显示了逻辑上的概念,物理内存上如何存储的,怎么写入的,怎么查询的,都是存储引擎需要负责的事,mysql为了实现不同的功能,提供了各式各样的存储引擎。
上面提到的mysql连接,缓存,解析,优化都数据mysql service,他们都会调用各式各样的api来访问后说的存储引擎。Mysql创建表的时候默认是InnoDB,可以通过EGNINE = MyISAM来指定搜索引擎。
字符集
计算机中只能存储二进制,那么字符怎么存储呢,于是建立字符与二进制的映射关系,建立映射关系需要解决两件事:
1、清楚界定字符范围(哪些字符集)。
2、字符集转成二进制叫编码,二进制转成字符集叫解码。
常用的字符集有这些ASCII、ISO 8859-1、GB2312、gbk、utf-8
ASCII:共收录128个字符,包括空格、标点符号、数字、大小写等。
ISO 8859-1:在ASCII基础上,收录256个字符。
GB2312:收录了汉字,拉丁字母等。
GBK:在GB2312上扩充,兼容GB2312。
Utf-8:收录地球上所有编码,并且在不断扩充。采用变长编码的方式,编码1~4个字节。比如占比小的则是小编码。
Mysql中的utf8就是utf8mb3,只使用1~3个字节,utf8mb4则使用1~4个字节,正常utf8mb3就够用了,后者则可以存储emoji表情。
一个字符集可能对应若干比较规则,utf8-general-ci是常见的比较规则,忽略大小写,utf8默认就是这个。Utf8-general-bin(binary)则是二进制的比较规则,不区分大小写的。(所以在排序的时候,如果排序没有区分大小写或者有异常,可以看看他的比较级是什么)
Mysql字符集的比较规则和字符集分为四个模块:服务器级别、数据库级别、表级别、列级别。
服务器级别:character_set_server 表示字符集,collation_server表示比较级别。
数据库级别:设置的时候通过character set 和collate来设置,查看的时候通过character_Set_database和collation_database,,如果数据库级别没有指定字符集和比较级,则继承服务器的字符集和比较级所在规则。
表级别:和数据库设置一样,如果表级别没有指定字符集和比较级,则继承数据库的字符集和比较级所在规则。
列级别:和表级别设置一样,如果列级别没有指定字符集和比较级,则继承表的字符集和比较级所在规则。
这上面有一个共同的特点,当修改了字符集,则自动变成当前字符集对应的比较级,如果修改了比较级,则自动变成对应的字符集。
Mysql中字符集的转换
如果存入的是utf-8的编码,然后解析的是gbk的,这时候就会解码失败,于是我们看到的就是一堆乱码。但如果存入的是utf8的编码,然后中间解码后再编码成gbk,之后再解码成gbk的,这时候就不会乱码。
Mysql有三个系统变量:character_set_client、character_set_connection、character_Set_result。
character_set_connection与客户端交互,获取消息,然后转为character_set_connection的字符集,后character_Set_result返回给另一个客户端。他们可以单独设置字符集,也可以通过set name统一设置。