加入收藏 | 设为首页 | 会员中心 | 我要投稿 湖南网 (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 表中可以快速取到表的行数。这

正如我们假如用剧本/措施来举办逐行的扫表操纵,实现上就会涉及下面 2 个 SQL:

  1. // SELECT id FROM t LIMIT 1; OR SELECT MIN(id)-1 FROM t; -> $last_id// SELECT id FROM t WHERE id > $last_id LIMIT 1; 

详细涉及到此例的代码,SQL 层到存储引擎层的挪用相关,读取阶段的挪用栈如下:(供参考)

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

我们可以看到,无论是哪一个分支的读取,最终都殊途同归于 row_search_mvcc函数。

以上是对 LOOP 中的代码做一些扼要的声名,下面来看 row_search_mvcc与 evaluate_join_record 怎样输出最终的 count 功效。

2.3 行可见性及 row_search_mvcc 函数

这里我们首要通过一组 case 和几个题目来看行可见性对 COUNT( * ) 的影响。

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

Q:对付SELECT COUNT( * ) FROM t可能SELECT MIN(id) FROM t操纵,第一次的读行操纵读到的是表 t 中 ( B+ 树最左叶节点 page 内 ) 的最小记录吗?( ha_index_first 为何也挪用 row_search_mvcc 来获取最小 key 值?)

A:不必然。纵然是MIN ( id ) 也不必然就读取的是 id 最小的那一行,由于也同样有行可见性的题目,现实上 index_read 取到的是 当前事宜内语句可见的最小 index 记录。这也反应了前面提到的 join_read_first 与 join_read_next “殊途同归”到 row_search_mvcc 是理所该当的。

Q:针对图中最后一问,假如事宜 X 是 RU ( Read-Uncommitted ) 断绝级别,且 C-Insert ( 100 ) 的完成是在 X-count( * )执行进程中 ( 仅扫描到 5 或 10 这笔记录 ) 完成的,那么 X-count( * ) 在事宜 C-Insert ( 100 ) 完成后,可否在之后的读取进程中看到 100 这笔记录呢?

A:MySQL 采纳”读到什么就是什么”的计策,即X-count( * )在后头可以读到 100 这笔记录。

2.4 evaluate_join_record 与列是否为空

Q:某一行怎样计入 count?

A:两种环境会将所读的行计入 count:

1、假如 COUNT 函数中的参数是某列,则会判定所读行中该列界说是否 Nullable以及该列的值是否为 NULL;若两者均为是,则不管帐入 count,不然将计入 count。

  • e.g. SELECT COUNT(col_name) FROM t
  • col_name可所以主键、独一键、非独一键、非索引字段

2、假如 COUNT 中带有 * ,则会判定这部门的整行是否为 NULL,假如判定参数为 NULL,则忽略该行,不然 count++。

  • e.g-1. SELECT COUNT(*) FROM t
  • e.g-2. SELECT COUNT(B.*) FROM A LEFT JOIN B ON A.id = B.id

Q: 出格地,对付 SELECT COUNT(id) FROM t,个中 id 字段是表 t 的主键,则怎样?

A:结果上等价于 COUNT( * )。由于无论是 COUNT( * ),照旧 COUNT ( pk_col ) 都是由于有主键从而充实断定索取数据不为 NULL,这类 COUNT 表达式可以用于获取当前可见的表行数。

Q: 用户层面临 InnoDB COUNT( * ) 的优化操纵题目

A:这个题目是业界认识的一个题目,扫描非空独一键可获得表行数,但所涉及的字节数也许会少许多(在表的行长与主键、独一键的长度相差较多时),相对的 IO 价钱小许多。

相干挪用栈参考如下:

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

二、数据布局:

Q:count 值存储在哪个内存变量里?

A:SQL 理会后,存储于表达 COUNT( * ) 这一项中,((Item_sum_count*)item_sum)->count

如下图所示回首我们之前“COUNT( * )前置流程”部门提到的 JOIN 布局。

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

即 SQL 理会器为每个 SQL 语句举办布局化,将其放在一个 JOIN 工具 ( join ) 中来表达。在该工具中建设并添补了一个列表 result_field_list 用于存放功效列,列表中每个元素则是一个功效列的 ( Item_result_field*) 工具 ( 指针 ) 。

在 COUNT( * )-case 中,功效列列表只包括一个元素,( Item_sum_count: public Item_result_field ) 范例工具 ( name = “COUNT( * )”),个中该类所特有的成员变量 count即为所求。

三、MyISAM 全表 COUNT( * )

因为 MyISAM引擎并不常用于现实营业中,仅做扼要描写如下:

  1. MyISAM-COUNT( * ) 操纵是 O(1) 时刻伟大度的操纵。
  2. 每张MyISAM表中存放了一个 meta 信息-count 值,在内存中与文件中各有一份,内存中的 count 变量值通过读取文件中的 count 值来举办初始化。
  3. SELECT COUNT( * ) FROM t 会直接读取内存中的表 t 对应的 count 变量值。
  4. 内存中的 count 值与文件中的 count 值由写操纵来举办更新,其同等性由表级锁来担保。
  5. 表级锁担保的写入串行化使得,统一时候全部用户线程的读操纵要么被锁,要么只会看到一种数据状态。

四、几个题目

(编辑:湖南网)

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

热点阅读