MySQL 8.0 新特性:哈希連接(Hash Join)

Java技術(shù)棧
www.javastack.cn
關(guān)注閱讀更多優(yōu)質(zhì)文章
MySQL 開(kāi)發(fā)組于 2019 年 10 月 14 日 正式發(fā)布了 MySQL 8.0.18 GA 版本,帶來(lái)了一些新特性和增強(qiáng)功能。其中最引人注目的莫過(guò)于多表連接查詢(xún)支持 hash join 方式了。
我們先來(lái)看看官方的描述:
https://dev.mysql.com/doc/refman/8.0/en/hash-joins.html
SELECT?*?
????FROM?t1?
????JOIN?t2?
????????ON?t1.c1=t2.c1;
CREATE?TABLE?t1?(c1?INT,?c2?INT);
CREATE?TABLE?t2?(c1?INT,?c2?INT);
CREATE?TABLE?t3?(c1?INT,?c2?INT);
EXPLAIN FORMAT=TREE命令可以看到執(zhí)行計(jì)劃中的 hash join,例如:mysql>?EXPLAIN?FORMAT=TREE
????->?SELECT?*?
????->?????FROM?t1?
????->?????JOIN?t2?
????->?????????ON?t1.c1=t2.c1\G
***************************?1.?row?***************************
EXPLAIN:?->?Inner?hash?join?(t2.c1?=?t1.c1)??(cost=0.70?rows=1)
????->?Table?scan?on?t2??(cost=0.35?rows=1)
????->?Hash
????????->?Table?scan?on?t1??(cost=0.35?rows=1)
SELECT?*?
????FROM?t1
????JOIN?t2?
????????ON?(t1.c1?=?t2.c1?AND?t1.c2?????JOIN?t3?
????????ON?(t2.c1?=?t3.c1);
mysql>?EXPLAIN?FORMAT=TREE
????->?SELECT?*?
????->?????FROM?t1
????->?????JOIN?t2?
????->?????????ON?(t1.c1?=?t2.c1?AND?t1.c2?????->?????JOIN?t3?
????->?????????ON?(t2.c1?=?t3.c1)\G
***************************?1.?row?***************************
EXPLAIN:?->?Inner?hash?join?(t3.c1?=?t1.c1)??(cost=1.05?rows=1)
????->?Table?scan?on?t3??(cost=0.35?rows=1)
????->?Hash
????????->?Filter:?(t1.c2?cost=0.70?rows=1)
????????????->?Inner?hash?join?(t2.c1?=?t1.c1)??(cost=0.70?rows=1)
????????????????->?Table?scan?on?t2??(cost=0.35?rows=1)
????????????????->?Hash
????????????????????->?Table?scan?on?t1??(cost=0.35?rows=1)
mysql>?EXPLAIN?FORMAT=TREE
????->?????SELECT?*?
????->?????????FROM?t1
????->?????????JOIN?t2?
????->?????????????ON?(t1.c1?=?t2.c1)
????->?????????JOIN?t3?
????->?????????????ON?(t2.c1?***************************?1.?row?***************************
EXPLAIN:?<not?executable?by?iterator?executor>
mysql>?EXPLAIN
????->?????SELECT?*?
????->?????????FROM?t1
????->?????????JOIN?t2?
????->?????????????ON?(t1.c1?=?t2.c1)
????->?????????JOIN?t3?
????->?????????????ON?(t2.c1?***************************?1.?row?***************************
???????????id:?1
??select_type:?SIMPLE
????????table:?t1
???partitions:?NULL
?????????type:?ALL
possible_keys:?NULL
??????????key:?NULL
??????key_len:?NULL
??????????ref:?NULL
?????????rows:?1
?????filtered:?100.00
????????Extra:?NULL
***************************?2.?row?***************************
???????????id:?1
??select_type:?SIMPLE
????????table:?t2
???partitions:?NULL
?????????type:?ALL
possible_keys:?NULL
??????????key:?NULL
??????key_len:?NULL
??????????ref:?NULL
?????????rows:?1
?????filtered:?100.00
????????Extra:?Using?where;?Using?join?buffer?(Block?Nested?Loop)
***************************?3.?row?***************************
???????????id:?1
??select_type:?SIMPLE
????????table:?t3
???partitions:?NULL
?????????type:?ALL
possible_keys:?NULL
??????????key:?NULL
??????key_len:?NULL
??????????ref:?NULL
?????????rows:?1
?????filtered:?100.00
????????Extra:?Using?where;?Using?join?buffer?(Block?Nested?Loop)
mysql>?EXPLAIN?FORMAT=TREE
????->?SELECT?*
????->?????FROM?t1
????->?????JOIN?t2
????->?????WHERE?t1.c2?>?50\G
***************************?1.?row?***************************
EXPLAIN:?->?Inner?hash?join??(cost=0.70?rows=1)
????->?Table?scan?on?t2??(cost=0.35?rows=1)
????->?Hash
????????->?Filter:?(t1.c2?>?50)??(cost=0.35?rows=1)
????????????->?Table?scan?on?t1??(cost=0.35?rows=1)
在全局或者會(huì)話(huà)級(jí)別設(shè)置服務(wù)器系統(tǒng)變量 optimizer_switch 中的 hash_join=on 或者 hash_join=off 選項(xiàng)。默認(rèn)為 hash_join=on。 在語(yǔ)句級(jí)別為特定的連接指定優(yōu)化器提示 HASH_JOIN 或者 NO_HASH_JOIN。
增加 join_buffer_size 的值,確保 hash join 可以在內(nèi)存中完成。 增加 open_files_limit 的值。
set?join_buffer_size=2097152000;
SET?@@cte_max_recursion_depth?=?99999999;
INSERT?INTO?t1
--?INSERT?INTO?t2
--?INSERT?INTO?t3
WITH?RECURSIVE?t?AS?(
??SELECT?1?AS?c1,?1?AS?c2
??UNION?ALL
??SELECT?t.c1?+?1,?t.c1?*?2
????FROM?t
???WHERE?t.c1?1000000
)
SELECT?*
??FROM?t;
mysql>?EXPLAIN?ANALYZE
????->?SELECT?COUNT(*)
????->???FROM?t1
????->???JOIN?t2?
????->?????ON?(t1.c1?=?t2.c1)
????->???JOIN?t3?
????->?????ON?(t2.c1?=?t3.c1)\G
***************************?1.?row?***************************
EXPLAIN:?->?Aggregate:?count(0)??(actual?time=22993.098..22993.099?rows=1?loops=1)
????->?Inner?hash?join?(t3.c1?=?t1.c1)??(cost=9952535443663536.00?rows=9952435908880402)?(actual?time=14489.176..21737.032?rows=1000000?loops=1)
????????->?Table?scan?on?t3??(cost=0.00?rows=998412)?(actual?time=0.103..3973.892?rows=1000000?loops=1)
????????->?Hash
????????????->?Inner?hash?join?(t2.c1?=?t1.c1)??(cost=99682753413.67?rows=99682653660)?(actual?time=5663.592..12236.984?rows=1000000?loops=1)
????????????????->?Table?scan?on?t2??(cost=0.01?rows=998412)?(actual?time=0.067..3364.105?rows=1000000?loops=1)
????????????????->?Hash
????????????????????->?Table?scan?on?t1??(cost=100539.40?rows=998412)?(actual?time=0.133..3395.799?rows=1000000?loops=1)
1?row?in?set?(23.22?sec)
mysql>?SELECT?COUNT(*)
????->???FROM?t1
????->???JOIN?t2?
????->?????ON?(t1.c1?=?t2.c1)
????->???JOIN?t3?
????->?????ON?(t2.c1?=?t3.c1);
+----------+
|?COUNT(*)?|
+----------+
|??1000000?|
+----------+
1?row?in?set?(12.98?sec)
mysql>?EXPLAIN?FORMAT=TREE
????->?SELECT?/*+??NO_HASH_JOIN(t1,?t2,?t3)?*/?COUNT(*)
????->???FROM?t1
????->???JOIN?t2?
????->?????ON?(t1.c1?=?t2.c1)
????->???JOIN?t3?
????->?????ON?(t2.c1?=?t3.c1)\G
***************************?1.?row?***************************
EXPLAIN:?<not?executable?by?iterator?executor>
1?row?in?set?(0.00?sec)
SELECT?/*+??NO_HASH_JOIN(t1,?t2,?t3)?*/?COUNT(*)
??FROM?t1
??JOIN?t2?
????ON?(t1.c1?=?t2.c1)
??JOIN?t3?
????ON?(t2.c1?=?t3.c1);
mysql>?CREATE?index?idx1?ON?t1(c1);
Query?OK,?0?rows?affected?(7.39?sec)
Records:?0??Duplicates:?0??Warnings:?0
mysql>?CREATE?index?idx2?ON?t2(c1);
Query?OK,?0?rows?affected?(6.77?sec)
Records:?0??Duplicates:?0??Warnings:?0
mysql>?CREATE?index?idx3?ON?t3(c1);
Query?OK,?0?rows?affected?(7.23?sec)
Records:?0??Duplicates:?0??Warnings:?0
mysql>?EXPLAIN?ANALYZE
????->?SELECT?COUNT(*)
????->???FROM?t1
????->???JOIN?t2?
????->?????ON?(t1.c1?=?t2.c1)
????->???JOIN?t3?
????->?????ON?(t2.c1?=?t3.c1)\G
***************************?1.?row?***************************
EXPLAIN:?->?Aggregate:?count(0)??(actual?time=47684.034..47684.035?rows=1?loops=1)
????->?Nested?loop?inner?join??(cost=2295573.22?rows=998412)?(actual?time=0.116..46363.599?rows=1000000?loops=1)
????????->?Nested?loop?inner?join??(cost=1198056.31?rows=998412)?(actual?time=0.087..25788.696?rows=1000000?loops=1)
????????????->?Filter:?(t1.c1?is?not?null)??(cost=100539.40?rows=998412)?(actual?time=0.050..5557.847?rows=1000000?loops=1)
????????????????->?Index?scan?on?t1?using?idx1??(cost=100539.40?rows=998412)?(actual?time=0.043..3253.769?rows=1000000?loops=1)
????????????->?Index?lookup?on?t2?using?idx2?(c1=t1.c1)??(cost=1.00?rows=1)?(actual?time=0.012..0.015?rows=1?loops=1000000)
????????->?Index?lookup?on?t3?using?idx3?(c1=t1.c1)??(cost=1.00?rows=1)?(actual?time=0.012..0.015?rows=1?loops=1000000)
1?row?in?set?(47.68?sec)
mysql>?SELECT?COUNT(*)
????->???FROM?t1
????->???JOIN?t2?
????->?????ON?(t1.c1?=?t2.c1)
????->???JOIN?t3?
????->?????ON?(t2.c1?=?t3.c1);
+----------+
|?COUNT(*)?|
+----------+
|??1000000?|
+----------+
1?row?in?set?(19.56?sec)

版權(quán)聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接和本聲明。本文鏈接:https://blog.csdn.net/horses/article/details/102690076






關(guān)注Java技術(shù)棧看更多干貨

評(píng)論
圖片
表情

