1 基础架构:一条sql查询语句如何执行?

分析一个最简单的查询

mysql> select * from T where ID=10;

MySQL基本架构示意图

大体来说,mysql可以分为server层和存储引擎层

Server层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖mysql的大多数核心服务功能,以及所有的内置函数,所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。

而存储引擎层负责数据的存储和提取,其架构模式是插件式的,支持innodb、myisam、memory等多个存储引擎。现在最常用的是innodb,从mysql5.5开始成为默认的存储引擎。

上图中,不同的存储引擎公用一个server层,也就是从连接器到执行部分。

连接器

第一步,先连接到db上,连接器负责跟客户端建立连接、获取权限、维持和管理连接

mysql -h$ip -P$port -u$user -p

连接命令中的mysql是客户端工具,用来跟服务器建立连接,在完成经典的tcp握手后,连接器就开始身份认证,输入用户名和密码

--如果用户名或密码不正确,收到一个--access denied for user错误

--如果通过,连接器就回到权限表查出该用户拥有的权限,之后,在这个连接里面的权限逻辑判断,都将依赖于此时读到的权限。

一个用户成功建立连接后,即使用管理员账号对这个用户的权限做了修改,也不会影响已经存在连接的权限,修改完成后,只有再新建的连接才会使用新的权限设置。

客户端如果太长时间没动静,连接器就会自动将他断开,参数wait_timeout控制,默认8小时。

如果连接被断开之后,客户端再次发送请求,就会收到一个错误提醒:lost connection to mysql server during query。如果要继续,就需要重连,然后再执行请求。

数据库里面,长连接是指连接成功后,如果客户端有持续请求,则一直使用同一个连接。短连接则是指每次执行完很少的几次查询就断开,下次查询再重新建立一个

建立连接的过程通常是比较复杂的,所以建议在使用过程中尽量减少建立连接的动作,也就是尽量使用长连接。

但是全部使用长连接后,可能会发现,有些时候mysql占用内存涨得特别快,这是因为mysql在执行过程中临时使用的内存时管理在连接对象里面,这些资源会在连接断开的时候才释放,所以如果长连接累积下来,可能导致内存占用太大,被系统强行(OOM),从现象上看就是mysql异常重启了。

怎么解决这个问题呢?

--1 定期断开长连接,使用一段时间,或者程序里面判断执行过一个占用内存的大查询后,断开连接,之后要查询再重连

--2 如果使用mysql 5.7 或更新版本,可以在每次执行一个比较大的操作后,通过执行mysql_reset_connection来重新初始化连接资源,这个过程不需要重连和重新做权限认证,但是会将连接恢复到刚刚创建完成时的状态。

查询缓存

连接建立完成后,可以执行select语句,第二步:查询缓存

Mysql拿到一个查询请求后,会先到查询缓存看,之前是不是执行过这条语句,之前执行过的语句及其结果可能会以key-value对的形式,被直接缓存在内存中,key是查询语句,value是查询的结果,如果你的查询能够直接在这个缓存中找到key,那么这个value就会被直接返回给客户端。

如果语句不在查询缓存中,就会继续后面的执行阶段,执行完成后,执行结果会被存入查询缓存,可以看到,如果查询命中缓存,mysql不需要执行后面的操作,就可以直接返回,这个效率会很高。

但是大多数情况下会建议不要使用查询缓存,因为查询缓存往往弊大于利。

查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查询缓存都会被清空,因此很可能把结果存起来,还没使用就被一个更新全部清空了。对于更新压力大的数据库来说,查询缓存的命中率会非常低。除非业务有一种静态表,很长时间才会更新一次,比如,一个系统配置表,

Mysql提供了”按需使用”的方式,可以将参数设置为query_cache_type=demand,这样对于默认的sql语句都不使用查询缓存,而对于确定要使用查询缓存的语句,可以显示的使用sql_cache

mysql> select SQL_CACHE * from T where ID=10;

在mysql 8.0版本已经将查询缓存功能删掉。

分析器

如果没有命中查询缓存,就要开始真正执行语句了,分析器会先做词法分析,mysql要从sql语句识别出字符串分别是什么,代表什么

做完词法分析,就要做语法分析,根据语法规则判断sql是否合法。--生成一个对应的解析树

如果语句不对,会收到you have an error in you sql syntax的错误提醒

mysql> elect * from t where ID=1;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'elect * from t where ID=1' at line 1

分析每一个字符串是什么代表什么

优化器

在开始执行之前,还要经过优化器的处理

优化器是在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联join的时候,决定各个表的连接顺序,

mysql> select * from t1 join t2 using(ID)  where t1.c=10 and t2.d=20;

--既可以先从表t1取出c=10的id值,再根据id值关联表t2,在判断t2里面的d是否=20

--页可以先从表t2里面取d=20的id值,再根据id关联t1,再判断t1里面的c是否=10

这两种执行方法的逻辑结果是一样,但是执行的效率会有不同,而优化器的作用就是决定选择使用哪一个方案。

执行器

开始执行的时候,要先判断一下对这个表t是否有执行查询的权限,如果没有,就会返回没有权限的错误,

mysql> select * from T where ID=10;

ERROR 1142 (42000): SELECT command denied to user 'b'@'localhost' for table 'T'

如果有权限,就打开表继续执行,打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口

比如这sql中的表t,id字段没有index,那么执行器的执行流程

--1 调用innodb引擎接口取这个表的第一行,判断id值是否=10,如果不则跳过,如果是则将这些行缓存在结果集中

--2 调用引擎接口取”下一行”,重复相同的判断逻辑,直到取到这个表的最后一行

--3 执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。

语句执行完成

对于有index的表,执行的逻辑也差不多,第一次调用的是”取满足条件的第一行”这个接口,之后循环去”满足条件的下一行”这个接口,这些接口在引擎中已经定义好

会在数据库的慢查询日志中看到一个rows_examined的字段,表示这个语句执行过程中扫描了多少行。这个值就是在执行器每次调用引擎获取数据行的时候累加的。

在有些场景下,执行器调用一次,在引擎内部扫描了多行,因此引擎扫描行数跟rows_examined并不是完全相同的。

思考题

如果在表t中没有字段k,而sql执行了select * from t where k=1,会报错列k不存在,这个错误是在上面那个阶段报出来的呢?

--

1 基础架构:一条sql查询语句如何执行?的更多相关文章

  1. MySQL 笔记整理(1) --基础架构,一条SQL查询语句如何执行

    最近在学习林晓斌(丁奇)老师的<MySQL实战45讲>,受益匪浅,做一些笔记整理一下,帮助学习.如果有小伙伴感兴趣的话推荐原版课程,很不错. 1) --基础架构,一条SQL查询语句如何执行 ...

  2. MySQL 笔记整理(2) --日志系统,一条SQL查询语句如何执行

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> 2) --日志系统,一条SQL查询语句如何执行 MySQL可以恢复到半个月内任意一秒的状态,它的实现和日志系统有关.上一篇中记录了一 ...

  3. 01.基础架构:一条SQL查询语句是如何执行的?学习记录

    01.基础架构:一条SQL查询语句是如何执行的?学习记录http://naotu.baidu.com/file/1c8fb5a0f2497c3a2655fed89099cb96?token=ff25d ...

  4. 一文读懂一条 SQL 查询语句是如何执行的

    2001 年 MySQL 发布 3.23 版本,自此便开始获得广泛应用,随着不断地升级迭代,至今 MySQL 已经走过了 20 个年头. 为了充分发挥 MySQL 的性能并顺利地使用,就必须正确理解其 ...

  5. mysql数据库系统学习(一)---一条SQL查询语句是如何执行的?

    本文基于----MySQL实战45讲(极客时间----林晓斌 )整理----->https://time.geekbang.org/column/article/68319 一.第一节:一条sq ...

  6. mysql系列-⼀条SQL查询语句是如何执⾏的?

    ⼀条SQL查询语句是如何执⾏的? ⼤体来说,MySQL 可以分为 Server 层和存储引擎层两部分 Server 层 Server 层包括连接器.查询缓存.分析器.优化器.执⾏器等,涵盖 MySQL ...

  7. 浅谈SQL优化入门:1、SQL查询语句的执行顺序

    1.SQL查询语句的执行顺序 (7) SELECT (8) DISTINCT <select_list> (1) FROM <left_table> (3) <join_ ...

  8. oracle中sql查询语句的执行顺序

    查询语句的处理过程主要包含3个阶段:编译.执行.提取数据(sql查询语句的处理主要是由用户进程和服务器进程完成的,其他进程辅助配合) 一.编译parse 在进行编译时服务器进程会将sql语句的正文放入 ...

  9. C# EF使用SqlQuery直接操作SQL查询语句或者执行过程

    Entity Framework是微软出品的高级ORM框架,大多数.NET开发者对这个ORM框架应该不会陌生.本文主要罗列在.NET(ASP.NET/WINFORM)应用程序开发中使用Entity F ...

随机推荐

  1. div的edit和drag(点击div可编辑、删除、拖动)

    1.可编辑: <div id="move" contentEditable="true">可编辑</div> 设置contentEdit ...

  2. UEditor使用报错Cannot set property 'innerHTML' of undefined

    仿用UEditor的setContent的时候报错,报错代码如下Uncaught TypeError: Cannot set property ‘innerHTML’ of undefined.调试u ...

  3. Java程序员集合框架面试题

    Java集合框架是最常被问到的Java面试问题,要理解Java技术强大特性,就有必要掌握集合框架.这里有一些实用问题,常在Java面试中问到. 1. 什么是Java集合API Java集合框架API是 ...

  4. newgrp - 登录到新的用户组中

    总览 (SYNOPSIS) newgrp [ group ] 描述 (DESCRIPTION) Newgrp 改变 调用者 的 用户组标识, 类似于 login(1). 调用者 仍旧 登录 在 系统 ...

  5. JavaEE高级-JPA学习笔记

    *JPA概述 *JPA是什么? - Java Persistence API :用于对象持久化的API - Java EE 5.0平台标准的ORM规范,使得应用程序以统一的方式访问持久化层 - JPA ...

  6. Codeforces 960 二进制构造子序列 完全二叉树shift模拟 主席树/MAP DP

    A #include <bits/stdc++.h> #define PI acos(-1.0) #define mem(a,b) memset((a),b,sizeof(a)) #def ...

  7. 1125. Chain the Ropes (25)

    Given some segments of rope, you are supposed to chain them into one rope. Each time you may only fo ...

  8. vue2.0 之 生命周期

     一.vue1.x与vue2.x生命周期的变化区别及含义表(图表摘自网络)   二.vue2.x生命周期图和各阶段具体含义 beforecreated:el 和 data 并未初始化 created: ...

  9. 第二组_学生会管理系统_APP端个人感想

    一:相关链接 1.相关源码链接: 1.学生会管理系统APP端:Code 2.学生会管理系统WEB端:Code 3.学生会管理系统后台:COde 2.相关文档和博客: 1.前期接口文档以及需求文档Doc ...

  10. php内置函数分析之strpos()

    PHP_FUNCTION(strpos) { zval *needle; zend_string *haystack; char *found = NULL; ]; zend_long offset ...