拧螺丝|主管老大是魔鬼吧?第一道就干掉了对方,我什么时候才能有新同事?

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 RDS MySQL Serverless,价值2615元额度,1个月
简介: 拧螺丝|主管老大是魔鬼吧?第一道就干掉了对方,我什么时候才能有新同事?

  今天真的是尴尬,主管老大丢了一份资料让我去面一个三年的Java后端,让我根据上面的面试答案酌情给分。

       这次面的小哥他上家公司资金充足的时候,招了很多人,他进去后就只需要负责数据库方面的工作,开发工作接触的很少。

       又刚好小面的部门在数据库方面人才不足,于是主管就把这个活丢小面头上了。(明明开会的时候主管自己跟领导说自己会好好把关的....)

       结果我拿着这份面试题进去后,就问了一句“你知道一条查询SQL是怎么执行的吗?

       对方就说不出话来了,很快就草草了事了,出门还撞上了正打算去旁听的主管,主管还问我怎么还没去面试?

       到现在这份资料还在我手里,忘了还回去。干脆就来写写这道让我印象深刻的面试题吧!

前言

       人们常说看待一个事儿千万不要直接陷入细节里,你应该先鸟瞰其全貌,这样能够帮助你从高维度理解问题。同样,对于 MySQL 的学习也是这样。平时我们使用数据库,看到的通常都是一个整体。比如下面这个最简单的一个查询语句:

select * from T where ID=10;

       我们看到的只是输入一条语句,返回一个结果,却不知道这条语句在 MySQL 内部的执行过程。

       所以今天我想和你一起把 MySQL 拆解一下,看看里面都有哪些“零件”,希望借由这个拆解过程,让你对 MySQL 有更深入的理解。这样当我们碰到 MySQL 的一些异常或者问题时,就能够直戳本质,更为快速地定位并解决问题。

执行一条SQL会经过哪些组件?

       下面是 MySQL 的基本架构示意图,从中你可以清楚地看到 SQL 语句在 MySQL 的各个功能模块中的执行过程。


       大体来说,MySQL的逻辑架构 可以分为 Server 层和存储引擎层两部分。

       要问为什么mysql的逻辑架构会分为两部分呢?因为mysql是插件式的,有不同的存储引擎,所以在执行器和优化器(主要包括索引的优化),会根据表设置的存储引擎进行选择。

逻辑架构

       Server 层包括连接器、查询缓存、分析器、优化器、执行器等。

       而存储引擎层负责数据的存储和提取。现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开始成为了默认存储引擎。也就是说,你执行 create table 建表的时候,如果不指定引擎类型,默认使用的就是 InnoDB。不过,你也可以通过指定存储引擎的类型来选择别的引擎,比如在 create table 语句中使用 engine=memory, 来指定使用内存引擎创建表。

连接器

       使用数据库的第一步,我们会从客户端连接到MySQL数据库上,到时候等待我们的第一关就是这个连接器。连接器负责跟客户端建立连接,获取权限,维持和管理连接。一般的连接指令是这样写的:

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

       输完命令后就要开始输入密码,你也可以在-p后面直接加密码,但是这样会导致你的密码泄漏,不建议在生产服务器上直接加密码。

输完密码后,连接器就会开始认证你的身份:

  1. 如果用户名或密码不对,你就会收到一个"Access denied for user"的错误,然后客户端程序结束执行。
  2. 如果用户名密码认证通过,连接器会到权限表里面查出你拥有的权限。之后,这个连接里面的权限判断逻辑,都将依赖于此时读到的权限。

       这意味着当你建立连接成功后,即便你这个账户被管理员修改了权限,无法使用select关键字,也不会影响到你已经建立连接后的使用。只要重新建立连接,重新获取权限信息后,你才无法使用select关键字。

       连接完成后,如果你没有后续的动作,这个连接就处于空闲状态,你可以在 show processlist 命令中看到它。文本中这个图是 show processlist 的结果,其中的 Command 列显示为“Sleep”的这一行,就表示现在系统里面有一个空闲连接。


       那么问题来了,空闲连接是怎么形成的?空闲连接多了,对系统有什么影响?如何避免空闲连接过多的情况?

       答:新建连接使用过后,一段时间不用就会变成空闲连接,因为空闲连接会占用内存,所以空闲连接多了,会极其耗费资源,所以记得给空闲连接设置过期时间即可。

注意:

  1. MySQL 在默认设置下,当一个连接的空闲时间超过8小时后,MySQL 就会断开该连接。
  2. 但是使用c3p0连接池时则会被以为该被断开的连接依旧有效,这种情况下,一旦向连接池发起请求连接的话,客户端在使用该失效连接的时候即抛出异常。
    对于这一点,要么定时使用连接,使得不会被MySQL断开,要么修改MySQL配置/etc/mysql/my.cnf,让默认时间变长,24小时(606024=604800)即可
set interactive_timeout=604800; 
set wait_timeout=604800;
  1. 要么就在项目配置文件里修改c3p0的时间 cpool.maxIdleTime=25200
  2. 这个时间的设置还需要根据业务来看待!因为使用长连接后,你可能会发现,有些时候 MySQL 占用内存涨得特别快,这是因为 MySQL 在执行过程中临时使用的内存是管理在连接对象里面的。这些资源会在连接断开的时候才释放。所以如果长连接累积下来,可能导致内存占用太大,被系统强行杀掉(OOM),从现象看就是 MySQL 异常重启了。
    解决方法:1、定期断开链接,使用时再发起长连接;2、mysql5.7以后可以通过设置mysql_reset_connection来定期重置链接。
查询缓存

       连接建立完成后,你就可以执行 select 语句了。执行逻辑就会来到第二步:查询缓存。

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

       注意:大多数情况下,不建议使用查询缓存,因为查询缓存失效非常频繁,只适用于常年不被修改的数据上。对于查询语句来说,但凡有一个表的更新,这个表的所有查询缓存都会被清空。除非你的业务就是有一张静态表,很长时间才会更新一次。

       好在 MySQL 也提供了这种“按需使用”的方式。你可以将参数 query_cache_type 设置成 DEMAND

       而默认的 SQL 语句一般都不使用查询缓存,如果你想对某条SQL进行缓存,可以通过添加SQL_CACHE关键字来达到目的。

select SQL_CACHE * from T where ID=10;

       需要注意的是,MySQL 8.0 版本直接将查询缓存的整块功能删掉了,也就是说 8.0 开始彻底没有这个功能了。

具体请查看MySQL 8.0 去除查询缓存功能的文章:        https://mysqlserverteam.com/mysql-8-0-retiring-support-for-the-query-cache/

分析器

       如果没有命中查询缓存,就要开始真正执行语句了。首先,MySQL 需要知道你要做什么,因此需要对 SQL 语句做解析。

       分析器先会做“词法分析”与“语义解析”。你输入的是由多个字符串和空格组成的一条 SQL 语句,MySQL 需要识别出里面的字符串分别是什么,代表什么。

过程:

  1. 识别传进来的字符串
  2. 根据传进来的字符串用语法规则进行判断
  3. 如果有错误,将会收到You have an error in your SQL syntax的报错
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

       一般语法错误会提示第一个出现错误的位置,所以你要关注的是紧接“use near”的内容。

优化器

       通过分析器,MySQL 就知道你要做什么了,数据库就要针对你的需求想一个最优的解决方案,也就是执行计划,这个最优方案选择的操作,这个就是优化器要做的事情了。

       优化器是在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联(join)的时候,决定各个表的连接顺序。比如你执行下面这样的语句,这个语句是执行两个表的 join:

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

它大抵有这两个可能:

  1. 既可以先从表 t1 里面取出 c=10 的记录的 ID 值,再根据 ID 值关联到表 t2,再判断 t2 里面 d 的值是否等于 20。
  2. 也可以先从表 t2 里面取出 d=20 的记录的 ID 值,再根据 ID 值关联到 t1,再判断 t1 里面 c 的值是否等于 10。

       这两种执行方法的逻辑结果是一样的,但是执行的效率会有不同,而优化器的作用就是决定选择使用哪一个方案。一条 SQL 语句可能有不同的执行逻辑(或者执行顺序),但是优化器就是选择最优的执行顺序。

执行器

       MySQL 通过分析器知道了你要做什么,通过优化器知道了该怎么做,于是就进入了执行器阶段,开始执行语句。

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

select * from T where ID=10;
ERROR 1142 (42000): SELECT command denied to user 'b'@'localhost' for table 'T'

       在工程实现上,如果命中查询缓存,会在查询缓存返回结果的时候,也会做权限验证。查询也会在优化器之前调用 precheck 验证权限。

其实在这里可能会有一个问题,比如

       我创建了一个没有select权限的用户,执行select * from T where k=1,报错“select command denied”,并没有报错“unknown column”,是不是可以说明是在打开表之后才判断读取的列不存在?

       答:这个是一个安全方面的考虑。你想想一个用户如果没有查看这个表的权限,你是会告诉他字段不对还是没权限?如果告诉他字段不对,其实给的信息太多了,因为没权限的意思还包含了:没权限知道字段是否存在。

小结

       今天介绍了 MySQL 的逻辑架构,希望你对一个 SQL 语句完整执行流程的各个阶段有了一个初步的印象。

对于全文,我会使用一种更直观的概念来解释他们的具体作用:

       连接器:门卫:想进请出示准入凭证(工牌、邀请证明一类)。我这边没有您的预约记录(查询缓存)。“你好,你是普通员工,只能进入办公大厅,不能到高管区域”此为权限查询。

       分析器:“您需要在公司里面找一张头发是黑色的桌子?桌子没有头发啊!臣妾做不到”

       优化器:“要我在A  B两个办公室找张三和李四啊?那我应该先去B办公室找李四,然后请李四帮我去A办公室找张三,因为B办公室比较近且李四知道张三具体工位在哪”

       执行器:“好了,找人的计划方案定了,开始行动吧,走你!糟糕,刚门卫大哥说了,我没有权限进B办公室”

大家复习的时候可以先尝试回答这些问题检查自己的掌握程度:

  1. MySQL的框架有几个组件, 各是什么作用?
  2. Server层和存储引擎层各是什么作用?
  3. you have an error in your SQL syntax 这个保存是在词法分析里还是在语法分析里报错?
  4. 对于表的操作权限验证在哪里进行?
  5. 执行器的执行查询语句的流程是什么样的?
相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
7月前
|
测试技术
软件测试面试者注意啦!尽量避开这个坑,千万别让培训机构割韭菜啦!
软件测试面试者注意啦!尽量避开这个坑,千万别让培训机构割韭菜啦!
|
8月前
|
开发工具 Python
嗖嗖的,再也不怕被嘲笑了!!!
嗖嗖的,再也不怕被嘲笑了!!!
|
传感器 监控 小程序
小猴打架
题目描述 一开始森林里面有N只互不相识的小猴子,它们经常打架,但打架的双方都必须不是好朋友。每次打完架后,打架的双方以及它们的好朋友就会互相认识,成为好朋友。经过N-1次打架之后,整个森林的小猴都会成为好朋友。 现在的问题是,总共有多少种不同的打架过程。
115 0
小猴打架
|
安全 程序员 开发者
程序员接私活,怎样防止做完不给钱?
首先跟大家说明一点,我们做 IT 类的外包开发,是非标品开发,所以很有可能在开发过程中会有这样那样的需求修改,而这种需求修改很容易造成扯皮,进而影响到费用支付,甚至出现做完了项目收不到钱的情况。
263 0
程序员接私活,怎样防止做完不给钱?
|
芯片
瞧!公务员的工作还可以这样干
盼啊盼,第六届世界互联网大会在乌镇如期而至。 在今天的大会上,小云带来了帮助公务员提升工作效率的“神器”,平头哥压箱底的“宝贝”...... 一起来深入了解下。
9193 0
瞧!这5000个爱管闲事的工程师干的好事.....
从 2018 年 4 月来到大爱清尘基金开始,师先存就没有正经过过几个周末。
10122 0