《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.pswp.cn/news/377111.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/377111.shtml
英文地址,請注明出處:http://en.pswp.cn/news/377111.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java 性能優化實戰記錄(2)---句柄泄漏和監控

前言: Java不存在內存泄漏, 但存在過期引用以及資源泄漏. (個人看法, 請大牛指正) 這邊對文件句柄泄漏的場景進行下模擬, 并對此做下簡單的分析.如下代碼為模擬一個服務進程, 忽略了句柄關閉, 造成不能繼續正常服務的小場景. 1 public class FileHandleLeakExample {2 3 p…

什么是Java文件?

Java文件 (Java files) The file is a class of java.io package. 該文件是java.io包的類。 If we create a file then we need to remember one thing before creating a file. First, we need to check whether a file exists of the same name or not. If a file of the sa…

繞過本地驗證提交HTML數據

我們在入侵一個網站,比如上傳或者自己定義提交的文件時,會在本地的代碼中遇到阻礙,,也就是過 濾,過濾有兩種,一種是在遠程服務器的腳本上進行的過濾,這段代碼是在服務器上運行后產生作用的,這種過 濾方式叫做遠程過濾;另一種是在我們的IE瀏覽器里執行的腳本過濾,就是說是在我們…

《dp補卡——343. 整數拆分、96. 不同的二叉搜索樹》

343. 整數拆分 1、確定dp數組以及下標含義。 dp[i]&#xff1a;分拆數字i&#xff0c;可以得到的最大的乘積 2、確定遞推公式&#xff1a; dp[i]最大乘積出處&#xff1a;從1遍歷j到i&#xff0c;j * dp[i-j] 與 j * (i-j)取最大值。( 拆分j的情況&#xff0c;在遍歷j的過程…

Adroid學習之 從源碼角度分析-禁止使用回退按鈕方案

有時候&#xff0c;不能讓用戶進行回退操作&#xff0c;如何處理&#xff1f; 查看返回鍵觸發了哪些方法。在打開程序后把這個方法禁止了。問題&#xff1a;程序在后臺駐留&#xff0c;這樣就會出現&#xff0c;其他時候也不能使用回退按鈕。如何處理&#xff0c;在onpase()時方…

騎士游歷問題問題_騎士步行問題

騎士游歷問題問題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…

Java中的類型轉換

類型轉換 (Typecasting) Typecasting is a term which is introduced in all the language similar to java. Typecasting是一個用與Java類似的所有語言引入的術語。 When we assign primitive datatype to another datatype. 當我們將原始數據類型分配給另一個數據類型時。 I…

讓crash文件中的內存地址變成函數名稱,

假如程序員編譯了inhouse給測試。 如果在測試過程中出現奔潰現象&#xff0c;我想程序員一般會來看Device Log 也就是 crash文件 如果crash文件遇到如下的情況&#xff0c;在重要的地方看不到函數名稱。我想是一件很奔潰的事情。 1 Exception Type: EXC_BAD_ACCESS (SIGSEGV)2…

《dp補卡——多重背包》

多重背包簡介&#xff1a; 有N種物品和一個容量為V的背包。第i種物品最多有Mi件可用&#xff0c;每件耗費的空間為Ci&#xff0c;價值為Wi。求解將哪些物品裝入背包可使得這些物品耗費的空間總和不超過背包容量&#xff0c;且價值總和最大。 將Mi件攤開&#xff0c;就是一個01背…

kafka消息確認ack_什么是確認(ACK)? ACK代表什么?

kafka消息確認ackACK&#xff1a;致謝 (ACK: Acknowledgment) An acknowledgment (ACK) is a signal that is passed among the communicating processes, computers, or devices to indicate acknowledgment, or delivery of the message, as a component of a communications…

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補卡——買賣股票問題》

目錄121. 買賣股票的最佳時機貪心dp思路滾動數組優化122. 買賣股票的最佳時機 II123. 買賣股票的最佳時機 III188. 買賣股票的最佳時機 IV309. 最佳買賣股票時機含冷凍期714. 買賣股票的最佳時機含手續費121. 買賣股票的最佳時機 貪心 取最左最小值&#xff0c;取最右最大值&…

oo0ooo0ooo0oo_OoO的完整形式是什么?

oo0ooo0ooo0ooOoO&#xff1a;外出 (OoO: Out of Office) OoO is an abbreviation of "Out of Office". OoO是“不在辦公室”的縮寫。 It is an expression, which is commonly used in the Gmail platform. It is written in the body or the subject of the email…

SP2010開發和VS2010專家食譜--第三章節--高級工作流(2)--為沙盒解決方案創建自定義活動...

盡管沙河解決方案功能有限&#xff0c;你仍然可以開發自定義活動&#xff0c;在SharePoint Designer中使用而不用改變web.config或添加.ACTION文件到根文件夾。 轉載于:https://www.cnblogs.com/crazygolf/p/3856795.html

sql where 1=1和 0=1 的作用

where 11; 這個條件始終為True&#xff0c;在不定數量查詢條件情況下&#xff0c;11可以很方便的規范語句。 一、不用where 11 在多條件查詢中的困擾 舉個例子&#xff0c;如果您做查詢頁面&#xff0c;并且&#xff0c;可查詢的選項有多個&#xff0c;同時&#xff0c;還讓用戶…