zoukankan      html  css  js  c++  java
  • MySQL架构与SQL执行流程(一)

    版权所有,转载请注明出处!

    本篇博客主要针对有有MySQL使用经验的读者。

    做技术就要知道技术的实现原理,如果只是停留在一个会用的层面,我觉得不是一个合格的程序员。(你肯定会说,我不要你觉得,我只要我觉得! +_+  ~~~)。

    1.MySQL发展史

    首先我们先看一下MySQL的发展史,如下表所示:(你们自己看就行了,反正我也是这块内容从其他地方抄过来的。Winking smile

    时间 里程碑
    1996年

    MySQL 1.0 发布。它的历史可以追溯到 1979 年,作者 Monty 用 BASIC 设计 的一个报表工具。

    1996年10月

    3.11.1 发布。MySQL 没有 2.x 版本。

    2000年

    ISAM 升级成 MyISAM 引擎。MySQL 开源。

    2003年

    MySQL 4.0 发布,集成 InnoDB 存储引擎。

    2005年

    MySQL 5.0 版本发布,提供了视图、存储过程等功能。

    2008年

    MySQL AB 公司被 Sun 公司收购,进入 Sun MySQL 时代。

    2009 年

    Oracle 收购 Sun 公司,进入 Oracle MySQL 时代。

    2010年

    MySQL 5.5 发布,InnoDB 成为默认的存储引擎。

    2016年

    发布 8.0.0 版本。为什么没有 6、7?5.6 可以当成 6.x,5.7 可以当 成 7.x。

    常用的版本应该是5.X和现在的8.X,至于8.X的一些新特性,就不做太多的介绍,大家可以自行百度一下。

    2.一条查询SQL语句是如何执行的?

    image

    首先上个图,从这个流程示意图中我们可以看出,当一个客户端或者是APP向MySQL数据库发送一条查询语句的时候(整个过程我们使用问答的形式进行阐述。):

    1.首先与MySQL建立连接,连接必然涉及到通信协议,那么MySQL支持哪些协议呢?

    在MySQL给出的官方文档中,有写到MySQL主要支持的协议有:

    ①Unix Socket

    ②TCP/IP

    另外还有命名管道(Named Pipes)和内存共享(Share Memory)的方式,这两种通信方式只能在 Windows 上面使用,一般用得比较少。这里不做过多介绍,因为不是重点。

    当连接建立之后,如果长时间不进行操作,MySQL会通过设置的连接断开时间终止已经建立的连接。

    使用以下命令可以查询MySQL设置的默认连接失效时间:

    (因为我使用的是客户端的博客园所以代码没办法格式化,涉及到代码部分就用蓝色字体表示吧。)

    show global variables like 'wait_timeout';  //查看当前数据库非交互式 (如JDBC)连接失效时长 

        

    image

    show global variables like 'interactive_timeout'; //查看当前数据库交互式 (如数据库工具)连接失效时长 

      image

    我们可以看出数据库默认的连接时长是28800秒,即8个小时。

    这里顺便说一下global和session的区别:global是基于全局的设置,而session是基于当前会话的设置。

    那么数据库应该怎样查看已经建立的连接?我们可以使用以show status命令进行查看:

    show global status like 'Thread%';

    image

    Threads_cached: 缓存中的线程连接数。

    Threads_connected: 当前打开的连接数。

    Threads_created:为处理连接创建的线程数。

    Threads_running:非睡眠状态的连接数,通常指并发连接数。

    每产生一个连接或者一个会话,在服务端就会创建一个线程来处理。反过来,如果要杀死会话,就是 Kill 线程。

    有了连接数,我们怎么知道每个连接的状态?可以使用show processlist命令进行查看。

    show processlist;

    image

    标红线的地方这里,因为我设置了读写分离,所以会多出来两个连接,这个可以忽略。

    为了效果更明显,我们后面的演示,都用Navicat Premium工具类来进行演示。

    image

    一些常见状态说明,可以参考MySQL官方文档给出的定义。

    image

    我们顺便思考一个问题:MySQL中允许最大的连接数是多少?

    在5.7的版本之后,默认允许的连接数是151,最大可设置成16384,(2^14)。

    因为我装的数据的版本是5.5版本,所以演示效果不是151,我们可以使用

    select version();命令来查询当前版本号

    image

    修改的命令为:

    set global max_connections = 1000;

    重启后有效。

    2.建立连接之后,首先经过的是MySQL中查询缓存。

    MySQL 内部自带了一个缓存模块。

    缓存的作用我们应该很清楚了,把数据以 KV 的形式放到内存里面,可以加快数据的读取速度,也可以减少服务处理的时间。但是为什么我们会对MySQL的缓存比较陌生,甚至没有听说过。

    因为MySQL的缓存默认是关闭的。可以使用以下语句进行查询:

    image

    默认关闭就是官方不推荐使用,为什么呢?因为MySQL的缓存对SQL的拼写相似度要求比较高,比如多一个空格或者少一个空格,查询缓存都会失败。我们可以基于ORM框架或者是redis进行数据的缓存。

    当然最新的MySQL8已经把查询缓存这块内容移除掉了。

    3.语法解析和预处理

    我们会有一个疑问,为什么我的一条SQL能被识别?加入我随便执行一个字符串,MySQL去报错了呢?MySQL是怎样知道我们输入的内容是错的?

    这里就涉及到了MySQL的Parser解析器和Preprocessor预处理模块。

    这里主要是对语句进行SQL语法进行词法和语法分析和语义解析。

    这块内容不做过多讲解,因为我对这块东西也不是特别感兴趣,大概就是一个套用正则解析的过程。

    词法分析就是把一个完整的 SQL 语句打碎成一个个的单词。

    第二步就是语法分析,语法分析会对 SQL 做一些语法检查,比如单引号有没有闭合,

    然后根据 MySQL 定义的语法规则,根据 SQL 语句生成一个数据结构。这个数据结构我

    们把它叫做解析树(select_lex)。

    解析器可以分析语法,但是它怎么知道数据库里面有什么表,表里面有什么字段呢?

    实际上还是在解析的时候报错,解析 SQL 的环节里面有个预处理器。

    它会检查生成的解析树,解决解析器无法解析的语义。比如,它会检查表和列名是

    否存在,检查名字和别名,保证没有歧义。

    预处理之后得到一个新的解析树。

    4.查询优化与查询执行计划

    得到解析树之后,是不是执行 SQL 语句了呢?

    这里我们有一个问题,一条 SQL 语句是不是只有一种执行方式?或者说数据库最终执行的 SQL 是不是就是我们发送的 SQL?

    这个答案是否定的。一条 SQL 语句是可以有很多种执行方式的,最终返回相同的结果,他们是等价的。但是如果有这么多种执行方式,这些执行方式怎么得到的?最终选

    择哪一种去执行?根据什么判断标准去选择?

    这个就是 MySQL 的查询优化器的模块(Optimizer)。

    查询优化器的目的就是根据解析树生成不同的执行计划(Execution Plan),然后选择一种最优的执行计划,MySQL 里面使用的是基于开销(cost)的优化器,那种执行计

    划开销最小,就用哪种。

    可以使用这个命令查看内存的开销:

    show status like 'Last_query_cost';

    1578667041(1)

    执行计划的查看主要用到了 explain这个命令,我们在执行SQL的时候使用这个命令可以查看到sql的执行计划明细,尤其在查看命中索引的时候,这个命令起到很大的作用。

    5.存储引擎

    在 MySQL 里面,支持多种存储引擎,他们是可以替换的,所以叫做插件式的存储引擎。

    我们怎样查看数据库的存储引擎呢?

    可以通过执行  show table status from `dbname`;来查看数据库使用的存储引擎。

    image

    我们还可以通过show engines;命令来查看当前数据库支持的那些存储引擎。

    image

    我们常用的两种存储引擎MyISAM和InnoDB这两种,而且在MySQL数据库中只有InnoDB存储引擎支持事务。

    那么存储引擎是怎样存储数据的?

    我们可以使用show variables like 'datadir';来查看数据存储引擎的存放目录。

    image

    任何一个存储引擎都有一个 frm 文件,这个是表结构定义文件。

    image

    不同的存储引擎存放数据的方式不一样,产生的文件也不一样,innodb 是 1 个, memory 没有,myisam 是两个。

    MyISAM和InnoDB存储引擎有什么区别呢?

    InnoDB: mysql 5.7 中的默认存储引擎。InnoDB 是一个事务安全(与 ACID 兼容)的 MySQL存储引擎,它具有提交、回滚和崩溃恢复功能来保护用户数据。InnoDB 行级锁(不升级为更粗粒度的锁)和 Oracle 风格的一致非锁读提高了多用户并发性和性能。InnoDB 将用户数据存储在聚集索引中,以减少基于主键的常见查询的 I/O。为了保持数据完整性,InnoDB 还支持外键引用完整性约束。

    特点:

    支持事务,支持外键,因此数据的完整性、一致性更高。

    支持行级别的锁和表级别的锁。

    支持读写并发,写不阻塞读(MVCC)。

    特殊的索引存放方式,可以减少 IO,提升查询效率。

    适合:经常更新的表,存在并发读写或者有事务处理的业务系统。

    MyISAM:应用范围比较小。表级锁定限制了读/写的性能,因此在 Web 和数据仓库配置中,它通常用于只读或以读为主的工作。

    特点:

    支持表级别的锁(插入和更新会锁表)。不支持事务。

    拥有较高的插入(insert)和查询(select)速度。

    存储了表的行数(count 速度更快)。

    (怎么快速向数据库插入 100 万条数据?我们有一种先用 MyISAM 插入数据,然后修改存储引擎为 InnoDB 的操作。)

    适合:只读之类的数据分析的项目。

  • 相关阅读:
    剑指 Offer 33. 二叉搜索树的后序遍历序列
    剑指 Offer 32
    OCR技术浅析-tesserOCR(3)
    OCR技术浅析-自写篇(2)
    OCR技术浅析-无代码篇(1)
    SVN服务器+客户端安装和配置
    Git命令集
    数组模拟队列与单调队列求解滑动窗口
    upper_bound与lower_bound
    图中连通块的划分
  • 原文地址:https://www.cnblogs.com/wudi521/p/12178533.html
Copyright © 2011-2022 走看看