-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch.xml
More file actions
32 lines (15 loc) · 11.6 KB
/
search.xml
File metadata and controls
32 lines (15 loc) · 11.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>MySQL逻辑架构</title>
<link href="2021/02/18/mysql-luo-ji-jia-gou/"/>
<url>2021/02/18/mysql-luo-ji-jia-gou/</url>
<content type="html"><![CDATA[<h2 id="MySQL逻辑架构"><a href="#MySQL逻辑架构" class="headerlink" title="MySQL逻辑架构"></a>MySQL逻辑架构</h2><p><img src="https://gitee.com/WJiangYi/typora-img/raw/master/uPic/MySQL%E9%80%BB%E8%BE%91%E6%9E%B6%E6%9E%84.png" alt="MySQL逻辑架构"></p><p>MySQL逻辑架构总体分为四层:</p><ul><li>连接层:负责连接客户端,进行授权认证及其它的安全解决方案。</li><li>服务层:包括连接器、查询缓存、分析器、优化器、执行器等,负责查询解析、分析、优化、缓存以及所有的内置函数(例如日期、时间、数字和加密函数等),所有跨存储引擎的功能都在这一层实现:存储过程、触发器、视图等。</li><li>引擎层:负责MySQL中数据的存储和提取。其架构模式是插件式的,提供的功能不同,服务层通过调用存储引擎层API进行通信,存储引擎层不会解析SQL(InnoDB除外,它会解析外键定义),不同存储引擎之间也不会相互通信,而只是简单地响应上层服务器的请求。从MySQL5.5.5版本开始,InnoDB成为了默认的存储引擎。</li><li>存储层:主要是将数据存储在运行的计算机文件系统之上,并完成与存储引擎的交互。</li></ul><h2 id="SQL语句的执行流程"><a href="#SQL语句的执行流程" class="headerlink" title="SQL语句的执行流程"></a>SQL语句的执行流程</h2><p>在了解了整个MySQL的逻辑架构之后,我们可以思考一下在SQL语句的执行过程中,每一层中的各个模块的作用是什么?并且整个流程是如何执行的?</p><img src="https://gitee.com/WJiangYi/typora-img/raw/master/uPic/MySQL查询语句执行流程.png" alt="MySQL查询语句执行流程" style="zoom:50%;" /><h3 id="执行流程"><a href="#执行流程" class="headerlink" title="执行流程"></a>执行流程</h3><ul><li>客户端通过连接器连接到服务器,并发送一条查询给服务器。</li><li>服务器先通过缓存组件查看缓存是否开启,开启则检查查询缓存,未开启则进入到解析器阶段。</li><li>服务器检查查询缓存,如果缓存中存在需要查询的数据,则直接返回存储在缓存中的结果。否则进入下一阶段。</li><li>如果缓存不存在查询数据,则进入解析器阶段。</li><li>通过解析器、优化器将SQL语句解析、优化生成对应的执行计划。</li><li>执行器根据优化器生成的执行计划,调用存储引擎中的API接口来执行查询。</li><li>将查询到的结果返回给客户端。(也会将结果放入缓存中,以便下一次查询使用)</li></ul><h2 id="连接器"><a href="#连接器" class="headerlink" title="连接器"></a>连接器</h2><p>在SQL语句执行的时候,首先需要进入到MySQL服务器,连接到对应的数据库中,这就需要通过连接器来发挥作用。连接器主要负责跟客户端建立连接、获取权限、维持和管理连接。</p><p>连接命令:</p><pre class=" language-markdown"><code class="language-markdown">mysql -h 主机名 -P 端口号 -u 用户名 -p参数说明:<span class="token code keyword"> 1. -h: 指定客户端要登陆的MySQL主机名,登陆本机(localhost/127.0.0.1)可以省略</span><span class="token code keyword"> 2. -P: 登陆主机的端口号。(注意是大写,跟密码-p区分开)</span><span class="token code keyword"> 3. -u: 登陆的用户名。</span><span class="token code keyword"> 4. -p: 登陆的密码。(可以写在参数后面,但不建议这样写)</span></code></pre><p>连接命令输入之后,客户端会与服务器进行TCP握手,然后进行身份认证,这时候就需要输入用户名和密码。</p><ul><li><p>如果用户名或密码不对,就会收到一个<code>Access denied for user</code>的错误,然后客户端程序结束执行。</p><img src="https://gitee.com/WJiangYi/typora-img/raw/master/uPic/MySQL密码错误Access denied for user.png" alt="MySQL密码错误Access denied for user" style="zoom:50%;" /></li><li><p>如果用户名密码认证通过,连接器会到权限表里面查出拥有的权限,之后,这个连接里面的权限判断逻辑都将依赖于此时读到的权限。(如果在连接状态下,管理员对用户权限进行修改,也不会影响到当前连接的权限,只有重新建立新的连接才会使用新的权限设置)</p><img src="https://gitee.com/WJiangYi/typora-img/raw/master/uPic/MySQL建立连接.png" alt="MySQL建立连接" style="zoom:50%;" /></li></ul><p>在验证成功过后,便能够连接上MySQL服务器了,这个时候可以使用 <code>show processlist;</code> 命令查看连接状态,如果不对数据库进行操作,它会一直处于空闲状态。下图中Command列显示为Sleep的这一行就代表现在系统中存在一个空闲状态。</p><img src="https://gitee.com/WJiangYi/typora-img/raw/master/uPic/MySQL processlist空闲状态.png" alt="MySQL processlist空闲状态" style="zoom:50%;" /><p>如果系统长时间处于空闲状态,客户端太久没有响应,连接器会自动将它断开。这个时间是由 <code>wait_timeout</code> 控制的,默认值是8小时。如果在连接被断开后,客户端重新发送请求的话,就会得到一个错误提示,这时候你就需要重新连接,才能进行请求了。</p><blockquote><p> 这样一来你可能会想,有些公司平常六点下班,另一天九点上班,这空闲时间已经超过了八个小时,每天上班后都需要对服务器进行重连,比较麻烦,有什么方法能够解决这个问题吗?</p></blockquote><p>能够解决的办法就是进行长连接,这里就需要了解一下数据库长连接和短连接的区别了:</p><ul><li>长连接是指连接成功后,如果客户端持续有请求,则一直使用同一个连接。</li><li>短连接是指每次执行完很少的几次查询就会断开连接,下一次查询重新建立新的连接。</li></ul><p>但在使用长连接后,会发现内存涨的特别快,这是因为MySQL在执行过程中临时使用的内存是管理在连接对象里面的,只有在断开连接的时候这些资源才会被释放。如果一直使用长连接,就会导致OOM(Out Of Memory),然后MySQL异常重启。</p><blockquote><p>那应该如何去解决这个问题呢?</p></blockquote><ul><li>可以定期断开长连接,使用一段时间后,或者程序里面判断执行过一个占用内存比较大的查询后就断开连接,需要的时候重连就好了。</li><li>MySQL 5.7 版本以后,在每次执行一个比较大的操作后,执行 <code>mysql_reset_connection</code> 可以重新初始化连接资源。这个过程不需要重连和重新做权限验证,但是会初始化连接的状态。</li></ul><h3 id="查询缓存"><a href="#查询缓存" class="headerlink" title="查询缓存"></a>查询缓存</h3><p>成功连接上数据库之后,就可以进入查询缓存了。</p><p>MySQL得到了一个查询请求之后,便会对缓存组件进行一个判断,查看是否开启了缓存,如果缓存开启了,则查询缓存中是否存在这条SQL语句。</p><blockquote><p>那么这条SQL语句是怎样存在缓存里面的呢?</p></blockquote><p>它是通过key-value的形式缓存在内存中,key是查询的语句,value是查询的结果。</p><ul><li>查询的时候会拿着这条语句去缓存中查询,如果存在对应的key,那么就将值value直接返回给客户端。</li><li>如果语句不在查询缓存中,就进入到后面的阶段。</li></ul><blockquote><p>既然查询这么快,那它一定非常好用吧?</p></blockquote><p>错,相反的,并不推荐使用查询缓存。</p><p>查询缓存失效非常频繁,只要对一个表进行更新,这个表上的所有查询缓存都会被清空,就很容易出现这个表的缓存还没来得及使用就可能直接被清空掉的情况,或者说缓存积累了很多,但一下就直接被清空完不能使用了。</p><p>这就会导致查询缓存的命中率变低,这种情况只有在那种表只用来查询而不更新的情况比较适用。</p><blockquote><p>解决这个问题的方法是什么呢?</p></blockquote><p>可以在SQL编写的时候进行调用。</p><p>MySQL中提供了 <code>query_cache_type=DEMAND</code> 参数用来对缓存进行按需使用,这种状态下,默认的缓存都是失效的,而对于需要查询缓存的语句,可以使用 ``SQL_CACHE` 进行指定调用。</p><pre class=" language-sql"><code class="language-sql"><span class="token keyword">select</span> SQL_NO_CACHE <span class="token operator">*</span> <span class="token keyword">from</span> test</code></pre><p>注意:MySQL8.0之后的版本没有查询缓存这个功能。</p><p>对应知识点:《高性能MySQL》 p309</p><h3 id="解析器"><a href="#解析器" class="headerlink" title="解析器"></a>解析器</h3><p>在没有命中查询缓存的情况下,就开始执行SQL语句了。SQL的每个单词的意思是什么,整个SQL语句的含义是什么便是解析器进行的工作。</p><p>解析器中通常分为词法分析和语法分析:</p><ul><li><p>词法分析:对单词、空格进行分析,MySQL会去判断每个字符串代表着什么,是关键字、表名,还是列名等等。</p></li><li><p>语法分析:根据词法分析获得的结果,语法分析会对整条SQL进行判断,查看它是否符合MySQL语法,如果语句不对,则会给你提示错误信息。</p><img src="https://gitee.com/WJiangYi/typora-img/raw/master/uPic/MySQL语法分析.png" alt="MySQL语法分析" style="zoom:50%;" /></li></ul><h3 id="优化器"><a href="#优化器" class="headerlink" title="优化器"></a>优化器</h3><p>在解析成功之后,MySQL就知道你需要进行什么样的操作,在执行SQL之前,优化器还会对SQL进行处理。</p><p>优化器的作用其实很好理解,就分为两个部分:索引的使用、执行的顺序。</p><ul><li>索引的使用:在平时建表的时候可能会去创建多个索引,优化器的执行中会去确认你使用了什么索引,并且使用哪个索引的效率会更高。</li><li>执行的顺序:在整条SQL中存在不同的条件、不同的表或者其它情况,在优化器中会出现不同的执行方案,最后进行选择使用。</li></ul><h3 id="执行器"><a href="#执行器" class="headerlink" title="执行器"></a>执行器</h3><p>在完成了解析和优化步骤过后,便会进入到执行器阶段,开始执行SQL语句。</p><p>开始执行的时候,要先判断一下你对这个表 有没有执行的权限,如果没有,就会返回没有权限的错误。如果有权限,执行器就会根据表的引擎定义,去调用到对应的引擎接口。</p><p>执行的时候,就一行一行的去判断是否满足条件,有索引的执行起来可能就好点,一行行的判断就像是接口都提前在引擎定义好了,所以它比较快。</p><p>数据库的慢查询日志可以查看<strong>rows_examined</strong>字段,表示语句执行过程中扫描多少行,<strong>explain</strong>可以看到执行计划,扫描了多少行。</p>]]></content>
<categories>
<category> MySQL </category>
</categories>
<tags>
<tag> MySQL </tag>
</tags>
</entry>
</search>