电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

MySQL的join buffer原理

瀏覽:74日期:2023-10-03 15:15:24
一、MySQL的join buffer

在MySQL對于join操作的處理過程中,join buffer是一個重要的概念,也是MySQL對于table join的一個重要的優化手段。雖然這個概念實現并不復雜,但是這個是實現MySQL join連接優化的一個重要方法,在'暴力'連接的時候可以極大提高join查詢的效率。

關于這個概念的權威說明當然是來自MySQL文檔中對于這個概念的說明,說明的文字不多,但是言簡意賅,說明了這個優化的主要實現思想:Assume you have the following join:

Table name Typet1 ranget2 reft3 ALLThe join is then done as follows: - While rows in t1 matching range - Read through all rows in t2 according to reference key - Store used fields from t1, t2 in cache - If cache is full - Read through all rows in t3 - Compare t3 row against all t1, t2 combinations in cache- If row satisfies join condition, send it to client - Empty cache - Read through all rows in t3 - Compare t3 row against all stored t1, t2 combinations in cache - If row satisfies join condition, send it to client二、join buffer cache存儲空間的分配

下面函數中table_count表示的就是所有join table中在該table之前的非const table數量,因為這個table要緩存自己之前所有table中的每條記錄中'需讀取'(tables[i].table->read_set置位)。

其中兩重循環每次執行都是復制下需要緩存的field的描述結構(及其對應的數據源),或者說,二重循環只是為了賦值和保存元數據,而最后的cache->buff=(uchar*) my_malloc(size,MYF(0))才是真正的分配滿足條件的記錄內容。

static intjoin_init_cache(THD *thd,JOIN_TAB *tables,uint table_count){…… for (i=0 ; i < table_count ; i++) { bool have_bit_fields= FALSE; uint null_fields=0,used_fields; Field **f_ptr,*field; MY_BITMAP *read_set= tables[i].table->read_set; for (f_ptr=tables[i].table->field,used_fields=tables[i].used_fields ; used_fields ; f_ptr++) { field= *f_ptr; if (bitmap_is_set(read_set, field->field_index)) {used_fields--;length+=field->fill_cache_field(copy);…… } } cache->length=length+blobs*sizeof(char*); cache->blobs=blobs; *blob_ptr=0; /* End sequentel */ size=max(thd->variables.join_buff_size, cache->length); if (!(cache->buff=(uchar*) my_malloc(size,MYF(0)))) DBUG_RETURN(1); /* Don’t use cache */ /* purecov: inspected */ cache->end=cache->buff+size; reset_cache_write(cache); DBUG_RETURN(0);}三、普通的多表查詢實現

這個'普通'當然也可以理解為'樸素'、'直觀'的意思,也是大部分情況下的執行流程。普通查詢其實就是對于對于各個表格進行遞歸調用,和矩陣的乘法一樣一樣的,這個對應非常直觀,也非常通用。

而這個常規的查詢動作就是通過sub_select函數來實現,這個函數本質性上是執行

tsecer_select(){for (r = first ; r != end ; r = next){if(sofartest()){nexttable.tsecer_select()}}}

其中的sofartest()表示'使用所有當前已讀取表格可以進行的判斷',也就是where中下推的表達式。例如 select * from a, b where a.a > 10 and b.b + a.a = 10,在a表讀取之后,其實已經可以執行 a.a > 10的判斷。當然這個是一個甚至算不上偽代碼的描述方法,而真正的代碼對應為:

enum_nested_loop_statesub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records){…… error= (*join_tab->read_first_record)(join_tab); rc= evaluate_join_record(join, join_tab, error);…… while (rc == NESTED_LOOP_OK) { error= info->read_record(info); rc= evaluate_join_record(join, join_tab, error); }…… return rc;}static enum_nested_loop_stateevaluate_join_record(JOIN *join, JOIN_TAB *join_tab, int error){…… if (select_cond) { select_cond_result= test(select_cond->val_int()); /* check for errors evaluating the condition */ if (join->thd->is_error()) return NESTED_LOOP_ERROR; }…… if (found) { enum enum_nested_loop_state rc; /* A match from join_tab is found for the current partial join. */ rc= (*join_tab->next_select)(join, join_tab+1, 0); if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS)return rc; if (join->return_tab < join_tab)return NESTED_LOOP_OK; /*Test if this was a SELECT DISTINCT query on a table thatwas not in the field list; In this case we can abort ifwe found a row, as no new rows can be added to the result. */ if (not_used_in_distinct && found_records != join->found_records)return NESTED_LOOP_NO_MORE_ROWS; }……}

這里可以看到,這個地方是一個遞歸,用來產生一個笛卡爾叉乘集合,從程序實現和數學表達上看都非常簡潔可愛。在MySQL的實現中,tsecer_select函數中的for循環大致相當sub_select中的while循環,而tsecer_select函數中循環體內的內容被放在了evaluate_join_record函數中,其中的sofartest對應evaluate_join_record::test(select_cond->val_int());tsecer_select中的nexttable.tsecer_select()語句對應evaluate_join_record::(*join_tab->next_select)(join, join_tab+1, 0)。

四、join buffer的select實現

當使用join buffer cache時,next_select函數指向sub_select_cache

enum_nested_loop_statesub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records){ enum_nested_loop_state rc; if (end_of_records) { rc= flush_cached_records(join,join_tab,FALSE); if (rc == NESTED_LOOP_OK || rc == NESTED_LOOP_NO_MORE_ROWS) rc= sub_select(join,join_tab,end_of_records); return rc; } if (join->thd->killed) // If aborted by user { join->thd->send_kill_message(); return NESTED_LOOP_KILLED; /* purecov: inspected */ } if (join_tab->use_quick != 2 || test_if_quick_select(join_tab) <= 0) { if (!store_record_in_cache(&join_tab->cache)) return NESTED_LOOP_OK; // There is more room in cache return flush_cached_records(join,join_tab,FALSE); } rc= flush_cached_records(join, join_tab, TRUE); if (rc == NESTED_LOOP_OK || rc == NESTED_LOOP_NO_MORE_ROWS) rc= sub_select(join, join_tab, end_of_records); return rc;}

結合MySQL文檔中的說明,這里的代碼意義就比較明顯。開始對于end_of_records的判斷對應的就是

if (!store_record_in_cache(&join_tab->cache)) return NESTED_LOOP_OK; // There is more room in cache return flush_cached_records(join,join_tab,FALSE);

對應

- Store used fields from t1, t2 in cache - If cache is full

其中store_record_in_cache函數會判斷cache是否已滿,如果cache可以放入更多的緩存,則把之前table的組合記錄存儲在cache中,并返回NESTED_LOOP_OK。注意:這個地方可以說是整個cache優化的關鍵,因為這里并沒有啟動對于table的掃描。反過來說,如果cache數據已經滿了,則調用flush_cached_records函數來進行下面的流程

- Read through all rows in t3 - Compare t3 row against all t1, t2 combinations in cache- If row satisfies join condition, send it to client - Empty cache

這個流程的特殊之處在于遍歷的驅動是通過對于table的每一條記錄來和cache中所有t1、t2組合來進行比較,來判斷是否滿足下推where條件(If row satisfies join condition),則執行join_tab->next_select函數(send it to client)。

static enum_nested_loop_stateflush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last){…… info= &join_tab->read_record; do {//遍歷t3表格所有記錄……for (i=(join_tab->cache.records- (skip_last ? 1 : 0)) ; i-- > 0 ;){//遍歷cache中所有t1、t2記錄組合 read_cached_record(join_tab); skip_record= FALSE; if (select && select->skip_record(join->thd, &skip_record)) {// reset_cache_write(&join_tab->cache); return NESTED_LOOP_ERROR; } if (!skip_record) {//滿足下推的where條件//執行下一個table的遍歷 rc= (join_tab->next_select)(join,join_tab+1,0); if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS) { reset_cache_write(&join_tab->cache); return rc; } }…… } while (!(error=info->read_record(info)));五、舉例來說明下這個流程

這個實現的核心思想并不復雜,結合具體的例子來看就更加的簡單直觀。舉個例子,其中使用兩個簡單的table,其中分別存儲一個x,和y的值,我們希望通過一個join操作來計算這兩個表格中所有的滿足 x

x + y

y == 5 * 5,也就是我們最常見的'勾三股四弦五'這樣的經典勾股數數值。

mysql> create table harry (x int);Query OK, 0 rows affected (0.03 sec) mysql> insert harry values (1),(2),(3),(4),(5);Query OK, 5 rows affected (0.00 sec)Records: 5 Duplicates: 0 Warnings: 0 mysql> create table tsecer (y int); Query OK, 0 rows affected (0.01 sec) mysql> insert tsecer values (1),(2),(3),(4),(5); Query OK, 5 rows affected (0.00 sec)Records: 5 Duplicates: 0 Warnings: 0 mysql> explain select * from harry, tsecer where x * x + y * y = 5 * 5;+----+-------------+--------+------+---------------+------+---------+------+------+--------------------------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+--------+------+---------------+------+---------+------+------+--------------------------------+| 1 | SIMPLE | harry | ALL | NULL | NULL | NULL | NULL | 5 ||| 1 | SIMPLE | tsecer | ALL | NULL | NULL | NULL | NULL | 5 | Using where; Using join buffer |+----+-------------+--------+------+---------------+------+---------+------+------+--------------------------------+2 rows in set (0.00 sec) mysql>1、不使用joinbuffer

在不使用join buffer的情況下,對于harry表的每個x值,對應的tsecer表都要進行一次全表掃描,之后使用這個x和y的組合判斷是否滿足x

x + y

y == 5 * 5這條件。由于x總共有5個值,所以tsecer需要全表掃描的次數就是5次。

2、使用joinbuffer

對于x的每個值,tsecer表在執行的時候先是把這個值緩存到joinbuffer中,如果buffer緩沖內容非空,那么把此時的x的值存儲在buffer中后直接返回;當join buffer滿或者是最后一條記錄的時候,此時開始啟動對于tsecer表的掃描,對于tsecer表中讀取的每一個記錄,結合前面緩存的每一個記錄,看是否滿足自己判斷條件。對于我們看到的例子,這個地方harry表的5個值都在緩存中,在tsecer表的掃描過程中,對于從tsecer中讀取的每一條記錄,結合緩存中的“每一條”緩存,判斷這個組合結果是否滿足條件,如果任意一個組很滿足,那么就繼續next_select。在這個使用buffer的例子中,可以看到這個地方只是對于tsecer表進行了一次掃描,而通常來說,數據庫的掃描代碼是最高的(因為要涉及到磁盤讀取),這樣使用buffer的方式將tsecer表的掃描降低為1次,所以這個效率提高很多,特別是在涉及到的多個table,并且/或者 每個table中的記錄數量都很多的情況下。

3、cache可以優化的原因

本質上說,這個效率提高的原因在于提高了從table中獲得的每條記錄的“利用率”,在使用直觀掃描方式時,table的全表掃描只是和一個組合進行匹配,而使用buffer之后則是和cache中的所有組合進行匹配。

以上就是MySQL的join buffer原理的詳細內容,更多關于MySQL join buffer的資料請關注好吧啦網其它相關文章!

標簽: MySQL 數據庫
相關文章:
主站蜘蛛池模板: 盐水蒸发器,水洗盐设备,冷凝结晶切片机,转鼓切片机,絮凝剂加药系统-无锡瑞司恩机械有限公司 | 石膏基自流平砂浆厂家-高强石膏基保温隔声自流平-轻质抹灰石膏粉砂浆批发-永康市汇利建设有限公司 | 阴离子聚丙烯酰胺价格_PAM_高分子聚丙烯酰胺厂家-河南泰航净水材料有限公司 | 玖容气动液压设备有限公司-气液增压缸_压力机_增压机_铆接机_增压器 | 深圳富泰鑫五金_五金冲压件加工_五金配件加工_精密零件加工厂 | 带锯机|木工带锯机圆木推台锯|跑车带锯机|河北茂业机械制造有限公司| | 微信小程序定制,广州app公众号商城网站开发公司-广东锋火 | 智慧食堂_食堂管理系统_食堂订餐_食堂消费系统—客易捷 | 胜为光纤光缆_光纤跳线_单模尾纤_光纤收发器_ODF光纤配线架厂家直销_北京睿创胜为科技有限公司 - 北京睿创胜为科技有限公司 | 四合院设计_四合院装修_四合院会所设计-四合院古建设计与建造中心1 | 礼堂椅厂家|佛山市艺典家具有限公司 | 湖南印刷厂|长沙印刷公司|画册印刷|挂历印刷|台历印刷|杂志印刷-乐成印刷 | 轻型地埋电缆故障测试仪,频响法绕组变形测试仪,静荷式卧式拉力试验机-扬州苏电 | 优考试_免费在线考试系统_培训考试系统_题库系统_组卷答题系统_匡优考试 | 诸城网站建设-网络推广-网站优化-阿里巴巴托管-诸城恒泰互联 | 中药二氧化硫测定仪,食品二氧化硫测定仪|俊腾百科 | 磁力链接搜索神器_BT磁力狗_CILIMAO磁力猫_高效磁力搜索引擎2024 | 磷酸肌酸二钠盐,肌酐磷酰氯-沾化欣瑞康生物科技 | 无锡网站建设_企业网站定制-网站制作公司-阿凡达网络 | 冲锋衣滑雪服厂家-冲锋衣定制工厂-滑雪服加工厂-广东睿牛户外(S-GERT) | 今日娱乐圈——影视剧集_八卦娱乐_明星八卦_最新娱乐八卦新闻 | 顺景erp系统_erp软件_erp软件系统_企业erp管理系统-广东顺景软件科技有限公司 | 熔体泵|换网器|熔体齿轮泵|熔体计量泵厂家-郑州巴特熔体泵有限公司 | 超声波焊接机_超音波熔接机_超声波塑焊机十大品牌_塑料超声波焊接设备厂家 | 厂房出售_厂房仓库出租_写字楼招租_土地出售-中苣招商网-中苣招商网 | 塑料检查井_双扣聚氯乙烯增强管_双壁波纹管-河南中盈塑料制品有限公司 | 聚合氯化铝-碱式氯化铝-聚合硫酸铁-聚氯化铝铁生产厂家多少钱一吨-聚丙烯酰胺价格_河南浩博净水材料有限公司 | 浙江工业冷却塔-菱电冷却塔厂家 - 浙江菱电冷却设备有限公司 | 气体检测仪-氢气检测仪-可燃气体传感器-恶臭电子鼻-深国安电子 | 冷藏车-东风吸污车-纯电动环卫车-污水净化车-应急特勤保障车-程力专汽厂家-程力专用汽车股份有限公司销售二十一分公司 | 飞利浦LED体育场灯具-吸顶式油站灯-飞利浦LED罩棚灯-佛山嘉耀照明有限公司 | 高压绝缘垫-红色配电房绝缘垫-绿色高压绝缘地毯-上海苏海电气 | 亮点云建站-网站建设制作平台| 杭州荣奥家具有限公司-浙江办公家具,杭州办公家具厂 | 插针变压器-家用电器变压器-工业空调变压器-CD型电抗器-余姚市中驰电器有限公司 | 车充外壳,车载充电器外壳,车载点烟器外壳,点烟器连接头,旅行充充电器外壳,手机充电器外壳,深圳市华科达塑胶五金有限公司 | 不锈钢发酵罐_水果酒发酵罐_谷物发酵罐_山东誉诚不锈钢制品有限公司 | vr安全体验馆|交通安全|工地安全|禁毒|消防|安全教育体验馆|安全体验教室-贝森德(深圳)科技 | 点焊机-缝焊机-闪光对焊机-电阻焊设备生产厂家-上海骏腾发智能设备有限公司 | FFU_空气初效|中效|高效过滤器_空调过滤网-广州梓净净化设备有限公司 | 雨燕360体育免费直播_雨燕360免费NBA直播_NBA篮球高清直播无插件-雨燕360体育直播 |