《MySQL 8.0.22执行器源码分析(4.1)Item_sum类以及聚合》

Item_sum类用于SQL聚合函数的特殊表达式基类。

这些表达式是在聚合函数(sum、max)等帮助下形成的。item_sum类也是window函数的基类。
聚合函数(Aggregate Function)实现的大部分代码在item_sum.h和item_sum.cc

聚合函数限制

不能在表达式的所有位置使用聚合函数,使用聚合函数应该有一些明确的限制。

在没有嵌套的查询中,select列表的表达式中,having自居中使用聚合函数是有效的,在where子句、form子句或group by子句则是无效的。

关于解释,这篇文章可以看看:https://blog.csdn.net/weixin_33725515/article/details/85997761

在带有嵌套子查询的查询中检测聚合函数是否有效的规则比较复杂:

如下列查询:

SELECT t1.a FROM t1 GROUP BY t1.a HAVING t1.a > ALL (SELECT t2.c FROM t2 WHERE SUM(t1.b) < t2.c).

在子查询的where子句中使用了聚合函数sum(),但是由于它包含在外部查询的having子句中,因此它是有效的。将针对主查询中定义的每个组而不是子查询的组来评估表达式sum。

又如下列查询:

SELECT t1.a FROM t1 GROUP BY t1.a HAVING t1.a > ALL(SELECT t2.c FROM t2 GROUP BY t2.c HAVING SUM(t1.a) < t2.c)

聚合函数可以在外部查询块和内部查询块中进行评估,如果我们为外部查询评估sum,则将得到t1.a乘上t1组中的基数。在这种情况下,sum(t1.a)被用作每个相关子查询中的常数。但是,也可以为内部查询评估sum。此时t1.a将是每个相关子查询的常数,并且对表t2的每个组执行求和。

因此,根据向哪个查询快分配聚合函数,可以获得不同的结果。

检测聚合函数的查询块的一般规则如下:

考虑一个聚合函数S(E),其中E是一个包含列引用C1,…,Cn的表达式。针对包含聚合函数S(E)的查询块Qi会解析所有列引用Ci。令Q为所有查询块Qi中最内部的查询块。(注意,S(E)绝对不能在包含子查询Q的查询的查询块聚合,否则S(E)将引用至少一个未绑定的列引用)。如果在允许聚合函数的Q的构造中使用函数S(E),则我们在Q中聚合S(E)。

否则:如果启用了ANSI SQL模式,则报告错误。如果没有启用,在允许使用S(E)的地方查找包含S(E)的最内部的查询块。聚合的位置取决于子查询包含在哪个子句中。当包含在where子句中,包含在选择列表中或包含在having子句时,结果不同。

一些成员说明

成员base_select包含对其中包含了聚合函数的查询块的引用。

成员aggr_select包含对其中使用了聚合函数的查询块的引用。

max_aggr_level字段保留聚合函数中包含的未绑定列引用的最大嵌套级别。在嵌套级别较小的子查询中不能包含聚合函数比max_aggr_level高。可以聚合在嵌套级别大于max_aggr_level的子查询中。

如果聚合函数中不包含任何列引用,如count(*),则max_aggr_level为-1。

字段max_sum_func_level将包含用作给定聚合函数的参数的子表达式的聚合函数的嵌套级别的最大值,但不会在此聚合函数内的任何子查询块中聚合。仅当s1.max_sum_func_level < s0.max_sum_func_level时,嵌套的聚合函数s1才能在聚合函数s0中使用。如果未在s0内的任何子查询中计算s1,则将聚合函数s1视为嵌套于集合函数s0。

当我们使用递归方法fix_fields遍历查询子表达式时,将检查使用集合函数的条件。当我们将此方法用于Item_sum类的对象时,首先,在下降时(下降不知道指什么意思),调用init_sum_func_check方法,该方法初始化检查时使用的成员。然后在上升过程中,调用方法check_sum_func,该方法验证设置的函数的用法,并在无效时报告错误。方法check_sum_func用于链接在包含的查询块中聚合的聚合函数的item。此类函数的循环链通过字段inner_sum_func_list附加到相应的select_lex结构。

窗口函数

关于什么是窗口函数,参考链接通俗易懂的学会:SQL窗口函数

大部分的聚合函数如(sum、count、avg)也可以用作窗口函数。此时有如下限制:

1、不使用任何聚合器

2、不支持distinct

3、val_* ( ) 的作用不只是返回函数的当前值:它首先将函数的参数累加到函数的状态。例如处理end_write_wf()包含WF输入的临时表。每个输入行都传递给copy_funcs(),后者调用WF的 val_ *()对其进行累加。

类型判断

很多时候我们要判断聚合函数的类型,那么首先要先判断当前的操作是否是聚合操作,然后再判断聚合操作的类型。

Item类有一个纯虚函数: virtual enum Type type() const =0; 其对应的Type在该类中定义为:

  enum Type {INVALID_ITEM = 0,FIELD_ITEM,FUNC_ITEM,SUM_FUNC_ITEM,STRING_ITEM,INT_ITEM,REAL_ITEM,NULL_ITEM,VARBIN_ITEM,COPY_STR_ITEM,FIELD_AVG_ITEM,DEFAULT_VALUE_ITEM,PROC_ITEM,COND_ITEM,REF_ITEM,FIELD_STD_ITEM,FIELD_VARIANCE_ITEM,INSERT_VALUE_ITEM,SUBSELECT_ITEM,ROW_ITEM,CACHE_ITEM,TYPE_HOLDER,PARAM_ITEM,TRIGGER_FIELD_ITEM,DECIMAL_ITEM,XPATH_NODESET,XPATH_NODESET_CMP,VIEW_FIXER_ITEM,FIELD_BIT_ITEM,VALUES_COLUMN_ITEM};

Item_sum从Item派生出来,除了type函数外,他还带有一个函数virtual enum Sumfunctype sum_func () const=0;在Item_sum中定义了Sumfunctype的类型。

 enum Sumfunctype {COUNT_FUNC,           // COUNTCOUNT_DISTINCT_FUNC,  // COUNT (DISTINCT)SUM_FUNC,             // SUMSUM_DISTINCT_FUNC,    // SUM (DISTINCT)AVG_FUNC,             // AVGAVG_DISTINCT_FUNC,    // AVG (DISTINCT)MIN_FUNC,             // MINMAX_FUNC,             // MAXSTD_FUNC,             // STD/STDDEV/STDDEV_POPVARIANCE_FUNC,        // VARIANCE/VAR_POP and VAR_SAMPSUM_BIT_FUNC,         // BIT_AND, BIT_OR and BIT_XORUDF_SUM_FUNC,         // user defined functionsGROUP_CONCAT_FUNC,    // GROUP_CONCATJSON_AGG_FUNC,        // JSON_ARRAYAGG and JSON_OBJECTAGGROW_NUMBER_FUNC,      // Window functionsRANK_FUNC,DENSE_RANK_FUNC,CUME_DIST_FUNC,PERCENT_RANK_FUNC,NTILE_FUNC,LEAD_LAG_FUNC,FIRST_LAST_VALUE_FUNC,NTH_VALUE_FUNC,ROLLUP_SUM_SWITCHER_FUNC};

可以通过这些类型来判断读当前具体的聚合操作。除此之外,还可以利用lex的一些helper函数来进行辅助判断,如is_single_grouped

bool is_single_grouped() const {return m_agg_func_used && group_list.elements == 0 &&m_having_cond == nullptr;
}

如果该函数返回true,则说明没有group by 也没有have

主要的聚合函数具体在代码中的类结构和继承关系

在这里插入图片描述
COUNT/SUM/AVG/STD/VAR_POP函数:
在这里插入图片描述
MIN/MAX函数:
在这里插入图片描述
BIT_OR/BIT_AND/BIT_XOR函数:
在这里插入图片描述

聚合过程(不带group by)

不带group by的聚合会使用辅助类Aggregator,而group by并不使用该辅助类。
在这里插入图片描述

在优化阶段需要进行setup,比如初始化distinct或者sorting需要临时表或者临时Tree结构,方便下阶段的聚合。

JOIN::optimize--> 
JOIN::make_tmp_tables_info--> 
setup_sum_funcs--> 
Item_sum::aggregator_setup-->  
Aggregator_simple::setup-->
Item_sum::setup-->

在执行阶段

AggregateIterator::Read()->
reset_and_add()->
aggregator_clear()aggregator_add()->
Aggregator::clear()、Aggregator::add()->
Item_sum_xxx::add()

在计算distinct聚合时,还需要实现aggregator::endup(),因为distinct_aggregator::add()只是通过某种方式采集了unique的行,但是并未保存,需要在这个阶段进行保存。这个过程可以理解为在distinct的聚合过程中(add)无法判断是否唯一。

注意group by场景下本身是通过临时表解决唯一问题的。

聚合过程(带group by)

MySQL对于带GROUP BY的聚合,通常采用了Temp table的方式保存了(GROUP BY KEY, AGGR VALUE)
具体交给迭代器TemptableAggregateIterator实现。

TemptableAggregateIterator::Init()->
init_tmptable_sum_functions()update_tmptable_sum_func()->
Item_sum::reset_field()、Item_sum::update_field()->

Item_sum继承于Item_result_field,意味着该类作为计算函数的同时也保存输出结果。具体可以看每个Item_sum子类的val_xxx实现,该函数负责对上层结果或者客户端结果进行输出。

对于特殊聚合函数如AVG\STD\VAR_POP等函数,在累加过程中,临时保存的变量值有多个,实际的输出结果必须通过加工处理,尤其是在group by场景下,多个临时变量需要保存到temp table中,下次累加时取出来,直到最终结果输出。所以需要额外的辅助类Item_result_field,帮助该聚合函数进行最终结果输出。

在这里插入图片描述
举例,对于Item_avg_field类的最终结果,需要通过Item_avg_field::val_xxx计算后进行输出。

调用顺序如下:

ExecuteIteratorQuery()->
Query_result_send::send_data()->
THD::send_result_set_row()->
Item::send()->
Item_avg_field::val_xxx

在这里插入图片描述
小TIPS:如果内核需要实现多线程并行计算聚合函数的时候,可以通过改造对中间结果输出save_in_field_inner函数,让每个中间结果如按照设计保存到相应的field->ptr中,保留到临时表中。

一些函数(待补全)

Item_sum::check_sum_func

验证聚合函数的语义要求。检查聚合函数的上下文是否允许对其进行聚合,并且当它是另一个聚合函数的参数时,需要直接或间接确保该函数将这两个聚合函数聚合在不同的查询块中。如果将聚合函数聚集在某个外部查询块中,则会将其添加到附加的聚集块查询item链inner_sum_func_list中。
tips:解析表达式时,必须为所有的聚合函数调用此函数,而且是以后缀顺序调用。

Item_sum::cleanup

使用后调用每个item。作用是释放所有分配的资源,例如动态内存。通过清除缓存的值为新的执行做准备。它不会删除准备期间分配的值,那些资源由析构函数释放。

参考

http://mysql.taobao.org/monthly/2019/05/02/
https://dev.mysql.com/doc/dev/mysql-server/latest/classItem__sum.html
MySQL 8.0.22源码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/377111.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java 性能优化实战记录(2)---句柄泄漏和监控

前言: Java不存在内存泄漏, 但存在过期引用以及资源泄漏. (个人看法, 请大牛指正) 这边对文件句柄泄漏的场景进行下模拟, 并对此做下简单的分析.如下代码为模拟一个服务进程, 忽略了句柄关闭, 造成不能继续正常服务的小场景. 1 public class FileHandleLeakExample {2 3 p…

骑士游历问题问题_骑士步行问题

骑士游历问题问题Problem Statement: 问题陈述&#xff1a; There is a chessboard of size NM and starting position (sx, sy) and destination position (dx,dy). You have to find out how many minimum numbers of moves a knight goes to that destination position? 有…

Android基础之用Eclipse搭建Android开发环境和创建第一个Android项目(Windows平台)...

一、搭建Android开发环境 准备工作&#xff1a;下载Eclipse、JDK、Android SDK、ADT插件 下载地址&#xff1a;Eclipse:http://www.eclipse.org/downloads/ JDK&#xff1a;http://www.oracle.com/technetwork/java/javase/downloads/jdk7u9-downloads-1859576.html Android SD…

《dp补卡——01背包问题》

目录01背包[416. 分割等和子集](https://leetcode-cn.com/problems/partition-equal-subset-sum/)[1049. 最后一块石头的重量 II](https://leetcode-cn.com/problems/last-stone-weight-ii/)[494. 目标和](https://leetcode-cn.com/problems/target-sum/)01背包 1、dp数组以及…

用JavaScript往DIV动态添加内容

参考&#xff1a;http://zhidao.baidu.com/link?url6jSchyqPiEYCBoKdOmv52YHz9r7MTBms2pK1N6ptOX1kaR2eg320mlW1Sr6n36hpOeOadBxC2rWWGuhZPbms-K <div id"show"></div>要填充的数据为: 这是一个测试例子.jquery&#xff1a;$(function(){ var data …

《dp补卡——完全背包问题》

N件物品和一个最多能背重量为W的背包。第i件物品的重量为weight[i]&#xff0c;得到的价值是value[i]。每件物品都有无限个(可以放入背包多次)&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 01背包和完全背包唯一不同在于遍历顺序上。 01背包的核心代码&#xff1a…

《dp补卡——多重背包》

多重背包简介&#xff1a; 有N种物品和一个容量为V的背包。第i种物品最多有Mi件可用&#xff0c;每件耗费的空间为Ci&#xff0c;价值为Wi。求解将哪些物品装入背包可使得这些物品耗费的空间总和不超过背包容量&#xff0c;且价值总和最大。 将Mi件摊开&#xff0c;就是一个01背…

CocoaAsyncSocket 套接字

CocoaAsyncSocket 套接字 https://github.com/robbiehanson/CocoaAsyncSocket Asynchronous socket networking library for Mac and iOS 用于iOS以及Mac的异步套接字网络库。 TCP GCDAsyncSocket and AsyncSocket are TCP/IP socket networking libraries. Here are the key…

谷歌浏览器设置缓存方法

谷歌浏览器设置缓存方法&#xff1a; 1、在桌面Google Chrome快捷方式&#xff0c;目标&#xff1a;找到 C:\Users\Splendid\AppData\Local\…\Application\chrome.exe 在这后面加上-Disk-Cache-Dir”Z:\TEMP” 注意: -Disk前面有空格&#xff0c;”Z:\TEMP” 是文件存放在Z盘T…

《dp补卡——子序列问题》

目录300. 最长递增子序列674. 最长连续递增序列718. 最长重复子数组1143. 最长公共子序列53. 最大子序和392. 判断子序列115. 不同的子序列583. 两个字符串的删除操作72. 编辑距离647. 回文子串 &#xff08;与 5.最长回文子串思路差不多&#xff09;516. 最长回文子序列300. 最…

《leetcode : 647. 回文子串 思考分析双指针解法》

647. 回文子串 如何确定是回文串&#xff1a; 找中心然后往两边扩散&#xff0c;判断是否对称即可。 在遍历中心点的时候&#xff0c;注意中心点可以是一个元素也可以是两个元素。 class Solution { public:int cal_two_extend(const string& s,int i,int j,int n){int re…

explain用法

explain用法 EXPLAIN SELECT …… 变体&#xff1a; 1. EXPLAIN EXTENDED SELECT …… 将执行计划“反编译”成SELECT语句&#xff0c;运行SHOW WARNINGS 可得到被MySQL优化器优化后的查询语句 2. EXPLAIN PARTITIONS SELECT …… 用于分区表的EXPLAIN 执行计划包含的信息 id…

转:Google论文之三----MapReduce

文章来自于&#xff1a;http://www.cnblogs.com/geekma/p/3139823.html MapReduce&#xff1a;大型集群上的简单数据处理 摘要 MapReduce是一个设计模型&#xff0c;也是一个处理和产生海量数据的一个相关实现。用户指定一个用于处理一个键值&#xff08;key-value&#xff09;…

《DBNotes:Join算法的前世今生》

目录NestLoopJoin算法Simple Nested-Loop JoinIndex Nested-Loop JoinBlock Nested-Loop JoinBatched Key AccessHash Join算法In-Memory Join(CHJ)On-Disk Hash Join参考链接在8.0.18之前&#xff0c;MySQL只支持NestLoopJoin算法&#xff0c;最简单的就是Simple NestLoop Joi…

UNITY3D与iOS交互解决方案

原地址&#xff1a;http://bbs.18183.com/thread-456979-1-1.html 本帖最后由 啊,将进酒 于 2014-2-27 11:17 编辑 “授人以鱼&#xff0c;不如授人以渔”&#xff0c;以UNITY3D调用iOS版的91SDK为例&#xff0c;利用C# / C / OBJ-C交互原理,本文将详细介绍UNITY3D与iOS之间交互…

AP in R

AP聚类算法是目前十分火的一种聚类算法&#xff0c;它解决了传统的聚类算法的很多问题。不仅简单&#xff0c;而且聚类效果还不错。这里&#xff0c;把前两天学习的AP算法在R语言上面的模拟&#xff0c;将个人笔记拿出来与大家分享一下&#xff0c;不谈AP算法的原理&#xff0c…

nginx 模块解析

nginx的模块非常之多&#xff0c;可以认为所有代码都是以模块的形式组织&#xff0c;这包括核心模块和功能模块&#xff0c;针对不同的应用场合&#xff0c;并非所有的功能模块都要被用到&#xff0c;附录A给出的是默认configure&#xff08;即简单的http服务器应用&#xff09…

《LeetcodeHot100非困难题补录》

最近比较闲&#xff0c;也比较焦虑&#xff0c;刷刷题吧 目录11. 盛最多水的容器22. 括号生成31. 下一个排列48. 旋转图像49. 字母异位词分组56. 合并区间75. 颜色分类79. 单词搜索114. 二叉树展开为链表141. 环形链表148. 排序链表152. 乘积最大子数组169. 多数元素207. 课程表…

《MySQL8.0.22:Lock(锁)知识总结以及源码分析》

目录1、关于锁的一些零碎知识&#xff0c;需要熟知事务加锁方式&#xff1a;Innodb事务隔离MVCC多版本并发控制常用语句 与 锁的关系意向锁行级锁2、锁的内存结构以及一些解释3、InnoDB的锁代码实现锁系统结构lock_sys_tlock_t 、lock_rec_t 、lock_table_tbitmap锁的基本模式的…

《Linux杂记:一》

目录CPU负载和CPU利用率CPU负载很高,利用率却很低的情况负载很低,利用率却很高常用linux命令常用的文件、目录命令常用的权限命令常用的压缩命令CPU负载和CPU利用率 可以通过 uptime , w 或者 top 命令看到CPU的平均负载。 Load Average :负载的3个数字,比如上图的0.57、0.4…