面试官:一条查询 SQL 到底做了什么事?请你来描述下!
mhr18 2024-10-18 06:57 22 浏览 0 评论
前言
日常运维和开发中,我们经常需要写查询 SQL。但是,大家知道一条查询 SQL 在MySQL 内部是如何执行的嘛?比如这条简单的 SQL:
select * from test_db.user_info_tab where user_id =123;
我们知道在 MySQL 客户端,输入一条查询 SQL,然后看到返回查询的结果。这条查询语句在 MySQL 内部到底是如何执行的呢?本文跟大家探讨一下哈,我们先来看下MySQL基本架构:
1、MySQL 基本架构
总体来说,MySQL大体分为两部分,分别是 Server 层和存储引擎层。
Server 层
它包括连接器、查询缓存、分析器、优化器、执行器等。比如存储过程,触发器,视图都是在这一层实现的。
- 连接器(Connection Manager):负责处理客户端与服务器之间的连接。它接受来自客户端的请求,并进行身份验证和权限检查,建立和管理连接。
- 查询缓存(Query Cache):在旧版 MySQL 中有,但在较新的版本中已不推荐使用。它能够缓存查询和对应的结果,以提高查询性能。然而,在高并发和大型数据库中,它反而可能成为性能瓶颈,因为它在某些情况下会引起锁和不必要的开销。
- 分析器(Parser):负责分析 SQL 查询语句,验证其语法和语义,确保查询的正确性。它将 SQL 语句转换成内部数据结构供优化器和执行器使用。
- 优化器(Optimizer):接收来自分析器的查询请求,并决定如何最有效地执行查询。优化器的目标是找到最佳的执行路径,选择合适的索引、连接顺序和访问方法,以提高查询性能。
- 执行器(Executor):负责执行优化器生成的执行计划,获取存储引擎返回的数据,并处理客户端请求。它与存储引擎交互,执行查询并返回结果给用户。
存储引擎层
它负责数据的存储和提取。MySQL 支持 InnoDB、MyISAM、Memory 等多个存储引擎。我们日常运维和开发中,一般用的存储引擎就是 InnoDB。从 MySQL 5.5 版本开始,InnoDB 就成为了默认的存储引擎。
介绍完 MySQL 基本架构,带大家看一下,每个组件,一条查询SQL主要做什么事:
2、连接器
我们要执行查询SQL,一般在MySQL客户端, 需要输入连接命令,连接到MySQL服务端。在MySQL服务端,就是连接器负责跟你的客户端建立连接、获取权限、维持和管理连接。
连接命令如下:
mysql -h(ip地址) -P(端口) -u(用户名) -p
输入完连接命令之后,我们接着输入正确的密码,经过经典的TCP握手之后,就可以成功连接到 MySQL 服务器啦,如下:
mysql -h 127.0.0.1 -P 3306 -u root -p
Enter password: ******
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 50
Server version: 8.0.31 MySQL Community Server - GPL
Copyright (c) 2000, 2022, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
如果输入密码错误,则会收到一个 Access denied 的错误信息,如下:
mysql -h 127.0.0.1 -P 3306 -u root -p
Enter password: *****
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
连接成功之后,大家就可以直接输入查询SQL,就可以看到结果啦。
mysql> select * from test_db.user_info_tab where user_id =123;
+---------+----------------+------+------+--------+---------+--------------------------+
| id | user_name | age | city | status | user_id | password |
+---------+----------------+------+------+--------+---------+--------------------------+
| 1570091 | XXXXXXXXX | 28 | 深圳 | 活跃 | 123 | 523da7ne+yndc5nb1zWWlA== |
+---------+----------------+------+------+--------+---------+--------------------------+
1 row in set (0.01 sec)
大家注意一下哈,如果连接成功后,没有后续的输入查询 SQL 等其他操作。这时候,这个连接是空闲的哈,可以用 show processlist 查看。
3、查询缓存
在老版本的 MySQL 中,连接成功后,我们执行查询 SQL,会先执行查询缓存。
也就是说 MySQL 接受到一个查询SQL请求时,会先去查询缓存看看,如果缓存有这条 SQL 的查询结果,会直接返回。如果查询缓存没有,就继续往下执行,执行完之后,把结果写入缓存。其中,这个查询缓存是 key-value 的结果,你可以把它理解为一个 map 吧,其中 key 就是这个查询 SQL,value 则是这个查询的结果。
同时,如果你查询的表进行更新的时候,会清空缓存的。一个表更新比较频繁的话,使用查询缓存命中率会很低,你刚查完放到缓存,更新SQL又清空了,就很不划算。有些时候,一些静态配置表,很少更新的,才建议使用查询缓存。其他更新频繁的表,则不建议使用查询缓存,你可以通过这个参数 query_cache_type 设值是否走查询缓存。
其实,MySQL 比较新的版本,如 8.0 已经废弃了查询缓存,并且相应的参数 query_cache_type 也不再存在。因为在高并发和大型数据库环境下,查询缓存可能导致性能问题,并且在实际测试中发现,禁用查询缓存可能会提高整体性能和可伸缩性。
4、分析器
如果查询SQL没有命中查询缓存的话,继续往下执行,就到分析器上场了。它负责分析 SQL 查询语句,验证其语法和语义,确保查询的正确性。
你扔个 SQL 给 MySQL 服务器,它肯定需要先解析,才知道这个 SQL 是做什么的,对吧。它会派出分析器,先做词法分析。你提交过来的查询SQL是由很多个字符创和空格组成的,MySQL 会先解析出这些字符串表示什么意思。
select * from test_db.user_info_tab where user_id =123;
它先把关键字 select 解析出来,然后把 user_info_tab 解析成表,user_id 解析成列名。做完词法分析之后,开始做语法分析。语法分析主要就是判断,你的 SQL 是否满足 MySQL 的语法。
如果你的 SQL 写错了,语法分析就会报错误提示:ERROR 1064 (42000): You have an error in your SQL syntax;
mysql> select * rom test_db.user_info_tab where user_id =123;
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 'rom test_db.user_info_tab where user_id =123' at line 1
平时大家看到这个错误的时候,只需要,关注关键词 syntax to use near 就可以快速知道哪里写错啦。比如这个例子,就是我的from写错了,少了f。
5、优化器
经过分析器之后,MySQL已经知道需要做什么了。但是在经过执行器之前,还会先经过优化器。优化器做的事情就是,怎么去做才是最好的。对于一条查询SQL来说就是:怎么去查是最佳效率的。
比如这个查询SQL:
select * from test_db.user_info_tab where user_id =123 and user_name='XX';
其中,在 user_info_tab 表中,user_id 为索引字段,user_name 也是索引字段。
这条SQL执行的时候,可能使用索引 user_id,也可能使用使用 user_name。选择不同的索引,执行效率是不一样的。具体怎么选择,就是优化器所做的事情。
大家是否还记得 explain。我们使用它加在我们查询的SQL,就可以帮助了解优化器在执行查询时,选择的执行计划和相应的优化策略。
经过优化器之后,就来到了执行器阶段。也就是真正执行查询SQL了。
6、执行器
select * from test_db.user_info_tab where user_id =123 ;
在要开始执行时候,会判断一下,该用户是否对这个SQL有查询的权限,如果没有,则会报权限错误。如果有权限的时候,打开表直接执行。执行的过程,其实类似于执行调用引擎提供的接口。
我们现在假设 user_id 不是索引字段,我们使用的是InnoDb存储引擎,这个查询SQL执行过程就是这样:
- 调用 InnoDb 存储引擎提供的接口,获取 user_info_tab 表的第一行。
- 判断 user_id 是不是为123,如果不是,跳过这一行。如果是,把这一行放到结果集。
- 调用 InnoDb 存储引擎提供的接口,获取 user_info_tab 表的下一行。
- 判断 user_id 是不是为123,如果不是,跳过这一行。如果是,把这一行放到结果集。
- 重复3、4步骤,一直扫描完 user_info_tab 表的所有行。最后把结果集返回客户端。
聊到这里,其实一条查询SQL的执行过程,已经讲完啦,是不是很简单呀~~
来源:公众号捡田螺的小男孩
相关推荐
- 【预警通报】关于WebLogic存在远程代码执行高危漏洞的预警通报
-
近日,Oracle官方发布了2021年1月关键补丁更新公告CPU(CriticalPatchUpdate),共修复了包括CVE-2021-2109(WeblogicServer远程代码执行漏洞)...
- 医院信息系统突发应急演练记录(医院信息化应急演练)
-
信息系统突发事件应急预案演练记录演练内容信息系统突发事件应急预案演练参与人员信息科参与科室:全院各部门日期xxxx-xx-xx时间20:00至24:00地点信息科记录:xxx1、...
- 一文掌握怎么利用Shell+Python实现完美版的多数据源备份程序
-
简介:在当今数字化时代,无论是企业还是个人,数据的安全性和业务的连续性都是至关重要的。数据一旦丢失,可能会造成无法估量的损失。因此,如何有效地对分布在不同位置的数据进行备份,尤其是异地备份,成为了一个...
- docker搭建系统环境(docker搭建centos)
-
Docker安装(CentOS7)1.卸载旧版Docker#检查已安装版本yumlistinstalled|grepdocker#卸载旧版本yumremove-ydocker.x...
- 基础篇:数据库 SQL 入门教程(sql数据库入门书籍推荐)
-
SQL介绍什么是SQLSQL指结构化查询语言,是用于访问和处理数据库的标准的计算机语言。它使我们有能力访问数据库,可与多种数据库程序协同工作,如MSAccess、DB2、Informix、M...
- Java21杀手级新特性!3行代码性能翻倍
-
导语某券商系统用这招,交易延迟从12ms降到0.8ms!本文揭秘Oracle官方未公开的Record模式匹配+虚拟线程深度优化+向量API神操作,代码量直降70%!一、Record模式匹配(代码量↓8...
- 一文读懂JDK21的虚拟线程(java虚拟线程)
-
概述JDK21已于2023年9月19日发布,作为Oracle标准Java实现的一个LTS版本发布,发布了15想新特性,其中虚拟线程呼声较高。虚拟线程是JDK21中引入的一项重要特性,它是一种轻量级的...
- 效率!MacOS下超级好用的Linux虚拟工具:Lima
-
对于MacOS用户来说,搭建Linux虚拟环境一直是件让人头疼的事。无论是VirtualBox还是商业的VMware,都显得过于笨重且配置复杂。今天,我们要介绍一个轻巧方便的纯命令行Linux虚拟工具...
- 所谓SaaS(所谓三维目标一般都应包括)
-
2010年前后,一个科技媒体的主编写一些关于云计算的概念性问题,就可以作为头版头条了。那时候的云计算,更多的还停留在一些概念性的问题上。而基于云计算而生的SaaS更是“养在深闺人未识”,一度成为被IT...
- ORA-00600 「25027」 「x」报错(报错0xc0000001)
-
问题现象:在用到LOB大对象的业务中,进行数据的插入,失败了,在报警文件中报错:ORA-00600:内部错误代码,参数:[25027],[10],[0],[],[],[],[],[...
- 安卓7源码编译(安卓源码编译环境lunch失败,uname命令找不到)
-
前面已经下载好源码了,接下来是下载手机对应的二进制驱动执行编译源码命令下载厂商驱动https://developers.google.com/android/drivers?hl=zh-cn搜索NGI...
- 编译安卓源码(编译安卓源码 电脑配置)
-
前面已经下载好源码了,接下来是下载手机对应的二进制驱动执行编译源码命令下载厂商驱动https://developers.google.com/android/drivers?hl=zh-cn搜索NGI...
- 360 Vulcan Team首战告捷 以17.5万美金强势领跑2019“天府杯“
-
2019年11月16日,由360集团、百度、腾讯、阿里巴巴、清华大学与中科院等多家企业和研究机构在成都联合主办了2019“天府杯”国际网络安全大赛暨2019天府国际网络安全高峰论坛。而开幕当日最激荡人...
- Syslog 日志分析与异常检测技巧(syslog发送日志配置)
-
系统日志包含有助于分析网络设备整体运行状况的重要信息。然而,理解并从中提取有效数据往往颇具挑战。本文将详解从基础命令行工具到专业日志管理软件的全流程分析技巧,助你高效挖掘Syslog日志价值。Gr...
- 从Oracle演进看数据库技术的发展(从oracle演进看数据库技术的发展的过程)
-
数据库技术发展本质上是应用需求驱动与基础架构演进的双向奔赴,如何分析其技术发展的脉络和方向?考虑到oracle数据库仍然是这个领域的王者,以其为例,管中窥豹,对其从Oracle8i到23ai版本的核...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle位图索引 (74)
- oracle基目录 (50)
- oracle批量插入数据 (65)
- oracle事务隔离级别 (53)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)