加入收藏 | 设为首页 | 会员中心 | 我要投稿 湖南网 (https://www.hunanwang.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程 > 正文

深入理解select count(*)底层究竟做了什么

发布时间:2019-06-15 04:14:44 所属栏目:编程 来源:Java技术架构
导读:SELECT COUNT( * ) FROM t是个再常见不外的 SQL 需求了。在 MySQL 的行使类型中,我们一样平常行使事宜引擎 InnoDB 作为(一样平常营业)表的存储引擎,在此条件下,COUNT( * )操纵的时刻伟大度为 O(N),个中 N 为表的行数。 而 MyISAM 表中可以快速取到表的行数。这
副问题[/!--empirenews.page--]

SELECT COUNT( * ) FROM t是个再常见不外的 SQL 需求了。在 MySQL 的行使类型中,我们一样平常行使事宜引擎 InnoDB 作为(一样平常营业)表的存储引擎,在此条件下,COUNT( * )操纵的时刻伟大度为 O(N),个中 N 为表的行数。

而 MyISAM 表中可以快速取到表的行数。这些实践履历的背后是奈何的机制,以及为什么必要/可所以这样,就是此文想要切磋的。

先来看一下轮廓: MySQL COUNT( * ) 在 2 种存储引擎中的部门题目:

深入领略select count(*)底层毕竟做了什么

下面就带着这些题目,以 InnoDB 存储引擎为主来举办接头。

一、InnoDB 全表 COUNT( * )

首要题目:

执行进程是奈何的?

怎样计较 count?影响 count 功效的身分有哪些?

count 值存在那边?涉及的数据布局是奈何的?

为什么 InnoDB 只能通过扫表来实现 count( * )?(见本文最后的题目)

全表COUNT( * )作为 table scan 范例操纵的一个 case,有什么风险?

COUNT(* )操纵是否会像SELECT *一样也许读取大字段涉及的溢出页?

1. 执行框架 – 轮回: 读取 + 计数

1.1 根基结论

全表扫描,一个轮回办理题目。

轮回内: 先读取一行,再抉择该行是否计入 count。

轮回内是一行一行举办计数处理赏罚的。

1.2 声名

简朴 SELELCT-SQL 的执行框架,类比 INSERT INTO … SELECT 是同样的进程。

深入领略select count(*)底层毕竟做了什么

下面会慢慢细化怎样读取与计数 ( count++ ) 。

2. 执行进程

引述: 执行进程部门,分为 4 个部门:

  • COUNT( * )前置流程: 从 Client 端发 SQL 语句,到 MySQL-Server端执行 SELECT 之前,为后头的一些叙述做一铺垫。
  • COUNT( * ) 流程: 扼要给出代码层面的流程框架及 2 个焦点步调的重点挪用栈部门。
  • 读取一行: 可见性及 row_search_mvcc函数,先容可见性怎样影响 COUNT( * ) 功效。
  • 计数一行: Evaluate_join_record与列是否为空,先容计数进程怎样影响 COUNT( * )功效。

假如读者但愿直接看怎样举办 COUNT( * ),那么也可以忽略 (1),而直接跳到 (2) 开始看。

2.1 COUNT( * ) 前置流程回想 – 从 Client 端发 SQL 到 sub_select 函数

为了使看到的挪用进程不太突兀,我们照旧先回想一下怎样执行到 sub_select函数这来的:

深入领略select count(*)底层毕竟做了什么

1.MySQL-Client 端发送 SQL 语句,按照 MySQL 通讯协议封包发送。

2.Mysql-Server端吸取数据包,由协议理会出 command 范例 ( QUERY ) 及 SQL 语句 ( 字符串 ) 。

3.SQL 语句颠末理会器理会输出为 JOIN类的工具,用于布局化地表达该 SQL 语句。

  1. PS: 这里的 JOIN 布局,不只仅是纯语法布局,而是已经举办了语义处理赏罚,大致地说,汇总了表的列表 (table_list )、方针列的列表 (target_list )、WHERE 前提、子查询等语法布局。在全表 COUNT( * )-case 中,table_list = [表“t”(别名也是“t”)],target_list = [方针列工具(列名为“COUNT( * )”)],虽然这里没有 WHERE 前提、子查询等布局。 

4.JOIN工具有 2 个重要的要领: JOIN::optimize(), JOIN::exec(),别离用于举办查询语句的优化 和 查询语句的执行。

  1. join->optimize(),优化阶段 (稍后 myisam 下全表 count( * )操纵会涉及这里的一点内容)。  
  2. join->exec(),执行阶段 ( 重点 ),包括了 InnoDB 下全表count( * ) 操纵的执行流程。  

5.join->exec() 颠末多少挪用,将挪用到sub_select函数来执行简朴 SQL,包罗 COUNT( * ) 。

6.END of sub_select 。

2.2 COUNT( * ) 流程 ( 于 sub_select 函数中 )

上层的流程与代码是较量简朴的,齐集在 sub_select 函数中,个中 2 类函数别离对应于前面”执行框架”部门所述的 2 个步调 – 读取、计数。先给出结论如下:

1.  读取一行:从相对顶层的 sub_select 函数颠末一番挪用,最终全部分支将挪用到 row_search_mvcc 函数中,该函数就是用于从 InnoDB 存储引擎所存储的B+-tree布局中读取一行到内存中的一个 buf (uchar * ) 中,待后续处理赏罚行使。

2.  这里会涉及行锁的获取、MVCC 及行可见性的题目。虽然对 于 SELECT COUNT( * ) 这类快照读而言,只会涉及 MVCC 及其可见性,而不涉及行锁。详情可跳至“可见性与 row_search_mvcc 函数”部门。

3.  计数一行: 代码层面,将会在 evaluate_join_record函数中对所读取的行举办评估,看其是否该当计入 count中 ( 等于否要count++ )。

简朴来说,COUNT(arg) 自己为 MySQL 的函数操纵,对付一行来说,若括号内的参数 arg ( 某列或整行 )的值若不是 NULL,则 count++,不然对该行不予计数。详情可跳至“ Evaluate_join_record 与列是否为空”部门。

这两个阶段对 COUNT( * )功效的影响如下: (两层过滤)

深入领略select count(*)底层毕竟做了什么

(编辑:湖南网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读