文件首頁
MySQL 8.4 參考手冊
相關文件 下載本手冊
PDF (美國信紙) - 39.9Mb
PDF (A4) - 40.0Mb
Man Pages (TGZ) - 258.5Kb
Man Pages (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 參考手冊  /  ...  /  區塊巢狀迴圈與批次索引鍵存取聯結

10.2.1.12 區塊巢狀迴圈與批次索引鍵存取聯結

在 MySQL 中,有一種批次索引鍵存取 (BKA) 聯結演算法可用,它同時使用對聯結資料表的索引存取和聯結緩衝區。BKA 演算法支援內部聯結、外部聯結和半聯結操作,包括巢狀外部聯結。BKA 的優點包括由於更有效率的資料表掃描而提升的聯結效能。此外,先前僅用於內部聯結的區塊巢狀迴圈 (BNL) 聯結演算法已擴充,並且可用於外部聯結和半聯結操作,包括巢狀外部聯結。

以下章節討論了擴充原始 BNL 演算法所依據的聯結緩衝區管理、擴充的 BNL 演算法和 BKA 演算法。如需半聯結策略的資訊,請參閱使用半聯結轉換最佳化 IN 和 EXISTS 子查詢述詞

區塊巢狀迴圈和批次索引鍵存取演算法的聯結緩衝區管理

MySQL 可以使用聯結緩衝區來執行內部聯結(無需對內部資料表進行索引存取),以及在子查詢扁平化之後出現的外部聯結和半聯結。此外,當對內部資料表進行索引存取時,也可以有效地使用聯結緩衝區。

當儲存感興趣的列欄位值時,聯結緩衝區管理程式碼可以稍微更有效率地利用聯結緩衝區空間:如果列欄位的值為 NULL,則不會在緩衝區中配置額外的位元組,並且會為VARCHAR類型的任何值配置最少的位元組數。

此程式碼支援兩種緩衝區類型,一般型和增量型。假設聯結緩衝區 B1 用於聯結資料表 t1t2,並且此操作的結果使用聯結緩衝區 B2 與資料表 t3 聯結

  • 一般聯結緩衝區包含來自每個聯結運算元的欄位。如果 B2 是一個一般聯結緩衝區,則放入 B2 的每一列r 都由來自 B1 的列 r1 的欄位和來自資料表 t3 的符合列 r2 的感興趣的欄位組成。

  • 增量聯結緩衝區僅包含來自第二個聯結運算元產生的資料表之列的欄位。也就是說,它是相對於第一個運算元緩衝區中的列的增量。如果 B2 是一個增量聯結緩衝區,則它包含列 r2 的感興趣的欄位以及指向 B1 中的列 r1 的連結。

增量聯結緩衝區始終是相對於先前聯結操作的聯結緩衝區的增量,因此來自第一個聯結操作的緩衝區始終是一般緩衝區。在剛剛給出的範例中,用於聯結資料表 t1t2 的緩衝區 B1 必須是一般緩衝區。

用於聯結操作的增量緩衝區的每一列僅包含來自要聯結的資料表之列的感興趣的欄位。這些欄位會增加對第一個聯結運算元所產生之資料表中符合列的感興趣的欄位的參考。增量緩衝區中的多列可以參考同一列 r,其欄位儲存在先前的聯結緩衝區中,只要所有這些列都符合列 r 即可。

增量緩衝區可以減少從先前聯結操作使用的緩衝區複製欄位的頻率。這樣可以節省緩衝區空間,因為在一般情況下,第一個聯結運算元產生的列可以由第二個聯結運算元產生的多列比對到。不需要製作來自第一個運算元的列的多個副本。由於減少了複製時間,增量緩衝區也可以節省處理時間。

系統變數 optimizer_switchblock_nested_loop 旗標控制雜湊聯結。

batched_key_access 旗標控制最佳化工具如何使用批次鍵存取聯結演算法。

預設情況下,block_nested_loopon,而 batched_key_accessoff。請參閱第 10.9.2 節,「可切換最佳化」。最佳化工具提示也可能適用;請參閱Block Nested-Loop 和批次鍵存取演算法的最佳化工具提示

關於半聯結策略的資訊,請參閱使用半聯結轉換最佳化 IN 和 EXISTS 子查詢述詞

外部聯結和半聯結的區塊巢狀迴圈演算法

MySQL BNL 演算法的原始實作已擴充以支援外部聯結和半聯結運算(後來被雜湊聯結演算法取代;請參閱第 10.2.1.4 節,「雜湊聯結最佳化」)。

當這些運算使用聯結緩衝區執行時,放入緩衝區的每一列都會提供一個比對旗標。

如果使用聯結緩衝區執行外部聯結運算,則會針對聯結緩衝區中的每一列檢查第二個運算元產生的資料表之每一列是否符合。找到符合項目時,會形成新的延伸列(原始列加上第二個運算元的欄),並將其傳送給剩餘聯結運算進行進一步的延伸。此外,會啟用緩衝區中符合列的比對旗標。檢查要聯結的資料表的所有列之後,會掃描聯結緩衝區。緩衝區中未啟用比對旗標的每一列都會透過 NULL 補數(第二個運算元中每個欄的 NULL 值)進行延伸,並傳送給剩餘聯結運算進行進一步的延伸。

系統變數 optimizer_switchblock_nested_loop 旗標控制雜湊聯結。

如需詳細資訊,請參閱第 10.9.2 節,「可切換最佳化」。最佳化工具提示也可能適用;請參閱Block Nested-Loop 和批次鍵存取演算法的最佳化工具提示

EXPLAIN 輸出中,當 Extra 值包含 Using join buffer (Block Nested Loop)type 值為 ALLindexrange 時,表示資料表使用 BNL。

關於半聯結策略的資訊,請參閱使用半聯結轉換最佳化 IN 和 EXISTS 子查詢述詞

批次鍵存取聯結

MySQL 實作了一種稱為批次鍵存取 (BKA) 聯結演算法的資料表聯結方法。當索引存取由第二個聯結運算元產生的資料表時,可以套用 BKA。與 BNL 聯結演算法類似,BKA 聯結演算法會使用聯結緩衝區來累積聯結運算的第一個運算元所產生的列的相關欄。然後,BKA 演算法會建置金鑰,以存取要聯結的資料表,以取得緩衝區中的所有列,並以批次方式將這些金鑰提交至資料庫引擎以進行索引查閱。金鑰會透過多範圍讀取 (MRR) 介面提交至引擎(請參閱第 10.2.1.11 節,「多範圍讀取最佳化」)。提交金鑰後,MRR 引擎函式會以最佳方式在索引中執行查閱,提取由這些金鑰找到的聯結資料表的列,並開始將符合的列饋送至 BKA 聯結演算法。每個符合的列都與聯結緩衝區中列的參考配對。

使用 BKA 時,join_buffer_size 的值定義了每次向儲存引擎發出的請求中金鑰批次的大小。緩衝區越大,對聯結運算的右手邊資料表進行的循序存取越多,這可以顯著提高效能。

若要使用 BKA,optimizer_switch 系統變數的 batched_key_access 旗標必須設定為 on。BKA 使用 MRR,因此 mrr 旗標也必須為 on。目前,MRR 的成本估算過於悲觀。因此,也必須使 mrr_cost_basedoff 才能使用 BKA。以下設定會啟用 BKA:

mysql> SET optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';

MRR 函式有兩種執行情境:

  • 第一種情境用於傳統的磁碟式儲存引擎,例如 InnoDBMyISAM。對於這些引擎,通常會一次將聯結緩衝區中所有列的金鑰提交至 MRR 介面。引擎特定的 MRR 函式會對提交的金鑰執行索引查閱,從中取得列 ID(或主鍵),然後依 BKA 演算法的請求,逐一提取所有這些選取之列 ID 的列。每個列都會返回一個關聯參考,以便存取聯結緩衝區中符合的列。列由 MRR 函式以最佳方式提取:它們會依照列 ID(主鍵)順序提取。這可以提高效能,因為讀取是以磁碟順序而非隨機順序進行。

  • 第二種情境用於遠端儲存引擎,例如 NDB。來自聯結緩衝區一部分列的金鑰套件,連同其關聯,由 MySQL 伺服器(SQL 節點)傳送至 MySQL Cluster 資料節點。作為回報,SQL 節點會收到符合列的一個套件(或多個套件)以及對應的關聯。BKA 聯結演算法會擷取這些列並建置新的聯結列。然後,會將一組新的金鑰傳送至資料節點,並使用從返回的套件中取得的列來建置新的聯結列。該過程會持續到將聯結緩衝區中的最後一個金鑰傳送至資料節點,且 SQL 節點已接收並聯結所有符合這些金鑰的列。這可以提高效能,因為由 SQL 節點傳送至資料節點的金鑰承載套件較少,表示它與資料節點之間執行聯結運算的回合次數較少。

在第一種情境中,會保留聯結緩衝區的一部分,以儲存索引查閱選取的列 ID(主鍵),並將其作為參數傳遞給 MRR 函式。

沒有特殊緩衝區來儲存為聯結緩衝區中的列建置的金鑰。相反地,會將為緩衝區中下一列建置金鑰的函式作為參數傳遞給 MRR 函式。

EXPLAIN 輸出中,當 Extra 值包含 Using join buffer (Batched Key Access)type 值為 refeq_ref 時,表示資料表使用 BKA。

區塊巢狀迴圈和批次鍵存取演算法的最佳化工具提示

除了使用 optimizer_switch 系統變數來控制最佳化工具在整個工作階段中使用 BNL 和 BKA 演算法之外,MySQL 還支援最佳化工具提示,以影響每個陳述式的最佳化工具。請參閱第 10.9.3 節,「最佳化工具提示」

若要使用 BNL 或 BKA 提示來啟用外部聯結的任何內部資料表的聯結緩衝,則必須為外部聯結的所有內部資料表啟用聯結緩衝。