一条select语句的执行原理

MySQL查询流程详解:从缓存到执行器
本文详细介绍了MySQL的查询处理步骤,包括查询缓存的废弃、解析器的词法和语法分析、优化器的选择执行路径以及执行器的权限判断和存储引擎交互。分析了查询缓存效率不高的原因,并强调了在优化器阶段对SQL性能的影响。

第一步:查询缓存

一、介绍

注意:MySQL8.0之后就抛弃了缓存功能。(因为查询缓存平均效率不高)MySQL8.0之前可通过query_cache_type参数开关查询缓存

当SQL开始执行时,Server会现在查询缓存中查找该SQL语句。之前性质过的语句及其结果会以key-value的形式缓存在内存中。遍历所有key,查找是否有和执行的SQL吻合的,如果查找到,则直接将结果返回给客户端;如果没有,就会进入到解析器阶段,且最终的执行结果会被存入缓存之中。

二、查询缓存效率不高的原因?

1、两个查询请求在任何字符上的不同(例如:空格、注释、 大小写),都会导致缓存不会命中。

2、缓存失效:当缓存系统涉及到的表的结构或数据被修改,那该表的所有高速缓存查询都将变为无效并从高速缓存中删除。此时,对于更新频繁地数据库,缓存不仅仅会频繁失效而命中率不高,还要不断维护缓存列表。

第二步:解析器

作用: 在解析器中对 SQL 语句进行语法分析、语义分析。

一、词法分析:

分析器先做词法分析,MySQL以此识别出SQL语句中的字符串含义。

二、语法分析

根据词法分析的结果,语法分析器(比如:Bison)会根据语法规则,判断输入的SQL语句是否满足MySQL语法。如果SQL语句正确,会生成语法树;如果不正确,则会进行错误提醒。

第三步:优化器

作用:确定SQL语句的执行路径,比如是根据全表检索,还是根据索引检索等。

总:一条查询语句可以有多种执行方式,最后都返回相同的结果,但是不同的执行方式效率不同。优化器的作用就是可以找到其中最好的执行计划。

对SQL的优化主要也是在这一步,可以进行逻辑优化和物理优化。

第四步:执行器

1、权限判定

  • 执行之前需要判断该用户是否具备权限。
  • 如果没有,就会返回权限错误。
  • 如果有权限,就打开表继续执行。
  • 打开表时,执行器会根据表的引擎定义,调用存储引擎的API对表进行读写。

注意:存储引擎API只是抽象接口,具体实现是根据表选择的存储引擎,从而调用下面的存储引擎层。

在 MySQL8.0 以下的版本,如果设置了查询缓存,这时会将查询结果进行缓存。

<think> 我们讨论了如何在Shell脚本中处理两个表格数据,现在用户询问如何查询SELECT *语句返回结果的记录条数。这是一个关于SQL查询的问题。 根据引用[1]和[3],SELECT语句的基本结构包括SELECT子句、FROM子句等。要获取返回结果的记录条数,我们可以使用SQLCOUNT聚合函数。 方法:将SELECT *替换为COUNT(*),这样就会返回满足条件的记录总数。 示例: 原始查询:SELECT * FROM table_name WHERE condition; 改为计数查询:SELECT COUNT(*) FROM table_name WHERE condition; 这样就会返回一个数字,即记录条数。 注意:COUNT(*)会统计所有行的数量,包括NULL值。如果只统计非NULL值的行,可以使用COUNT(column_name)。 另外,引用[2]和[4]提到了查询效率和数据类型的影响。对于大型表,使用COUNT(*)可能较慢,但它是获取记录数的标准方法。如果表非常大,且只需要近似值,有些数据库系统(如MySQL的InnoDB)可能有更快的近似方法(例如使用SHOW TABLE STATUS),但准确计数还是用COUNT(*)。 因此,用户只需将原来的SELECT *语句改为SELECT COUNT(*)即可,同时保留相同的WHERE条件(如果有的话)。 例如: 原语句SELECT * FROM employees; 计数语句SELECT COUNT(*) FROM employees; 如果有限制条件,如部门为销售部: 原语句SELECT * FROM employees WHERE department = 'Sales'; 计数语句SELECT COUNT(*) FROM employees WHERE department = 'Sales'; 这样就会返回销售部门的员工数量。 生成相关问题: 1. 如何优化大表的COUNT(*)查询? 2. COUNT(1)和COUNT(*)有什么区别? 3. 如何在SQL查询中同时返回数据和记录总数? </think> 要查询 `SELECT *` 语句返回结果的记录条数,只需将 `SELECT *` 替换为 `SELECT COUNT(*)` 即可。以下是详细方法和示例: ### 方法说明 1. **基本语法**: ```sql SELECT COUNT(*) AS total_rows FROM 表名 [WHERE 条件]; ``` 2. **说明**: - `COUNT(*)`:统计所有满足条件的行数(包括NULL值) - `AS total_rows`:可选,为结果列命名 - `WHERE`:可选,添加过滤条件 3. **执行效率**: - 对比 `SELECT *`:`COUNT(*)` 仅返回单个数字,避免传输大量数据 - 数值型字段统计最快(引用[4]原理)[^4] ### 示例场景 #### 1. 统计整张表的行数 ```sql -- 统计 employees 表总记录数 SELECT COUNT(*) AS employee_count FROM employees; ``` 输出示例: ``` employee_count -------------- 1000 ``` #### 2. 带条件的计数 ```sql -- 统计薪资大于5000的员工数 SELECT COUNT(*) AS high_salary_count FROM employees WHERE salary > 5000; ``` #### 3. 结合GROUP BY分组计数 ```sql -- 按部门统计员工数量 SELECT department_id, COUNT(*) AS dept_employee_count FROM employees GROUP BY department_id; ``` ### 性能优化技巧 1. **索引优化**: ```sql -- 在WHERE条件字段添加索引 CREATE INDEX idx_salary ON employees(salary); ``` 2. **近似计数**(百万级数据适用): ```sql -- MySQL快速估值(误差<1%) SHOW TABLE STATUS LIKE 'employees'; ``` 查看结果中的 `Rows` 字段值[^2] 3. **分页统计优化**: ```sql -- 获取第10-20条记录时同时返回总数(引用[2]改进)[^2] SELECT SQL_CALC_FOUND_ROWS * FROM employees LIMIT 10 OFFSET 9; SELECT FOUND_ROWS() AS total_count; ``` > **重要提示**:`COUNT(1)` 与 `COUNT(*)` 性能基本一致,但 `COUNT(column)` 会跳过NULL值且效率更低[^3]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值