MYSQL——SQL语句到底怎么执行

查询语句执行流程

MySQL 查询语句执行流程

查询缓存(Query Cache)

MySQL内部自带了一个缓存模块,默认是关闭的。主要是因为MySQL自带的缓存应用场景有限。

  • 它要求SQL语句必须一摸一样
  • 表里面的任何一条数据发生变化时,该表所有缓存全部失效

在MySQL 5.8中,查询缓存已经被移除了。

语法解析和预处理(Parser & Preprocessor)

假如我们随便执行一个字符串 like SQL,服务器会报一个1064的错:

1064 - 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 'fkdljasklf' at line 1

服务器时怎么知道我输入的内容时错误的呢?

又或者,我输入一个语法完全正确的SQL,但是表名不存在, 它又是怎么发现的?

这就是MySQL的解析器(Parser)和预处理器(Preprocessor)。他们做的事情就是对SQL语句进行词法和语法分析和语义的解析

词法分析

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

比如一个简单SQL语句:

mysql 复制代码
select name from user where id = 1;

它会打碎成8个符号,记录每个符号是什么类型,从哪里开始到哪里结束。

语法分析

词法分析后,接下来就是语法分析。语法分析会对SQL做一些语法检查,比如单引号有无闭合,然后根据MySQL定义的语法规则,根据SQL语句生成一个数据结构,该数据结构我们称它为解析树。

预处理器(Preprocessor)

如果表名错误,会在预处理器处理时报错。

它会检查生成的解析树,解决解析器无法解析的语义。比如,它会检查表名和列名是否存在,检查名字和别名,保证没有歧义。

查询优化(Query Optimizer)与查询执行计划

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

答案是否定的。一条SQL语句是可以又很多种执行方式的。但是若有这么多执行方式,这些执行方式怎么得到的?最终选择哪一种去执行?根据什么标准去选择的?

这就是MYSQL查询优化器干的事。

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

mysql 复制代码
-- 使用如下命令查询查询的开销
show status like 'Last_query_cost'; -- 代表需要随机读取一个 4k 的数据页才能完成查找

如果我们想知道优化器是怎么工作的,它生成了几种执行计划,每种执行计划的cost是多少,怎么做?

查看优化器得到的执行计划

https://dev.mysql.com/doc/internals/en/optimizer-tracing.html

首先我们要启用优化器的追踪(默认是关闭的)

mysql 复制代码
show variables like 'optimizer_trace';
set optimizer_trace = "enable=on";

注意:开启这开关是会消耗性能的。 因为它要把优化分析的结果写到表里面,所以不要轻易开启或者查看之后关闭它(on改成off)

接着,我们执行一个SQL语句,优化器会生成执行计划:

mysql 复制代码
select t.tcid from teacher t,teacher_contact tc where t.tcid = tc.tcid; 

此时优化器分析过程就会记录到系统表里面了,我们可查询

mysql 复制代码
select * from information_schema.optimizer_trace\G 

expanded_query是优化后的SQL语句。

considered_execution_plans 里面列出了所有的执行计划。

记得关掉它

mysql 复制代码
set optimizer_trace="enabled=off"; -- 关闭优化器追踪
show variables like 'optimizer_trace'; -- 查看关闭结果
优化器可以做什么

MySQL优化器能处理那些优化类型呢?

  • 当我们对多张表进行关联查询时,以哪张表的数据作为基准表
  • select * from user where a = 1 and b = 2 and c = 3 ,如果c = 3结果有100条,b=2结果有200条,a=1结果有300条,你觉得会先执行哪个过滤?
  • 如果条件里面存在一些恒等或恒不等式,是否可以移除
  • 查询数据,能否直接从索引里面取到值
  • count()、min()、max()函数,能否从索引里面直接取到值等
优化器得到的结果

优化器最终会把解析树变成一个查询执行计划,查询执行计划是一个数据结构。

这个执行计划是不是一定是不是最优的执行计划?不一定,因为MySQL也可能覆盖不到所有的执行计划。

MySQL提供了一个执行计划工具。我们在SQL语句前面加上EXPLAIN,就可以看到执行计划信息。

mysql 复制代码
explain select name from user where id = 1;

更新语句执行流程

首先提个问题,您觉得索引会对更新语句生效嘛?或者对更新操作性能有影响嘛?

答案是肯定的,因为更新操作是包含查看操作的。也就是首先将更新数据查询出来放到内容,然后再内存中进行更新,最后写回磁盘。

  1. 客户端首先将SQL语句传入MySQL服务端
  2. 数据库服务器将 name = 666的数据查询出来放到内存,然后数据库服务告诉存储引擎,将name字段修改为涛哥
  3. 存储引擎将修改结果更新到数据库缓存中
  4. 存储引擎记录 redo log,并将这行记录状态置为prepare
  5. 存储引擎通知数据库服务,数据已修改,可提交事务
  6. 数据库服务将操作日志写入bin log中
  7. 通知存储引擎提交事务
  8. 将redo log里这个事务的相关记录状态置为commit状态
相关推荐
每天敲200行代码43 分钟前
MySQL 事务管理
数据库·mysql·事务
巴里巴气1 小时前
MongoDB索引及其原理
数据库·mongodb
程序员勋勋11 小时前
Redis的String数据类型底层实现
数据库·redis·缓存
不修×蝙蝠2 小时前
MySQL 全详解:从入门到精通的实战指南
数据库·mysql·索引·最左前缀
我的ID配享太庙呀3 小时前
Django 科普介绍:从入门到了解其核心魅力
数据库·后端·python·mysql·django·sqlite
不辉放弃4 小时前
kafka的消费者负载均衡机制
数据库·分布式·kafka·负载均衡
拉姆哥的小屋4 小时前
用 Flask 打造宠物店线上平台:从 0 到 1 的全栈开发实践
数据库·oracle·flask
小悟空4 小时前
[AI 生成] Flink 面试题
大数据·面试·flink
liliangcsdn5 小时前
mac neo4j install & verifcation
数据库·neo4j
Cyanto5 小时前
MyBatis-Plus高效开发实战
java·开发语言·数据库