📖

TiDBソースコード輪読会補遺: Join Order Greedy Solver(1)

2024/09/09に公開

前回まででLeft Deep Treeの話をしてきました。今回は実際にTiDBでJoin Orderを決める際のデフォルトのアルゴリズム、Greedy Solverを見ていきます。

アルゴリズムはDP(動的計画法)とGreedyの2つありますが、この選択は tidb_opt_join_reorder_threathold というパラメーターによって制御されており、このパラメーターの値より結合するテーブル数が多い場合はGreedyが利用されます。
デフォルトは0になっており、基本的に結合が発生するとGreedyが利用されるというわけです。

論理最適化

Join Orderを決める(TiDBでは、Join Reorderと呼ばれています)アルゴリズムの前に、それを呼び出す論理最適化部分のコードを見ていきます。

最適化のエントリーポイントは、logicalOptimize です。
https://github.com/pingcap/tidb/blob/42b624cbdedbd2f29386427fae0c539041647e09/pkg/planner/core/optimizer.go#L1120

論理最適化では、あらかじめ決められたルールを順番に適用していきます(logicalOptRuleインターフェースのoptimizeメソッドを呼び出す)が、その中の一つにJoin Reorderを行うjoinReOrderSolverがあります。

https://github.com/pingcap/tidb/blob/42b624cbdedbd2f29386427fae0c539041647e09/pkg/planner/core/optimizer.go#L97-L122

このjoinReOrderSolver::optimizeメソッドはoptimizeRecursive メソッドを呼び出し、ここで実際の最適化が行われます。
https://github.com/pingcap/tidb/blob/42b624cbdedbd2f29386427fae0c539041647e09/pkg/planner/core/rule_join_reorder.go#L237

Join Reorder

optimizeRecursive では、ヒント句の処理などを省略すると、だいたい下記のような流れになっています。

1. Join Groupの抽出

複数のJOINが連続して行われるとき、例えば SELECT ... FROM A JOIN B JOIN C ... みたいな場合に、この一連のJOINをフラットにした配列を作成します。

https://github.com/pingcap/tidb/blob/42b624cbdedbd2f29386427fae0c539041647e09/pkg/planner/core/rule_join_reorder.go#L244

この関数の中には今回立ち入りませんが、コメントにある通り一連のJOINのツリーをフラットにしたグループを返します。

https://github.com/pingcap/tidb/blob/42b624cbdedbd2f29386427fae0c539041647e09/pkg/planner/core/rule_join_reorder.go#L31-L38

2. GreedyまたはDPの適用

冒頭説明したGreedyの判定をここで行っています。
https://github.com/pingcap/tidb/blob/42b624cbdedbd2f29386427fae0c539041647e09/pkg/planner/core/rule_join_reorder.go#L270

https://github.com/pingcap/tidb/blob/42b624cbdedbd2f29386427fae0c539041647e09/pkg/planner/core/rule_join_reorder.go#L292-L303

というところで、次回はGreedyの中身 joinReorderGreedySolver::solve を見ていきたいと思います。

おまけ: ヒントとOuter Join

コードを読んでいくと、ヒント(Leading Hint)とOuter Joinの判定が散乱しているのがわかります。これはヒントやOuter JoinはJoin Orderを固定する効果を持つからだと思われます。
SQLではJOINしたテーブルに別名をつけることもできるので、その別名に対してヒントがあるとその構造を保存するといったロジックがあり、コーナーケースの把握は大変だと思いました。

TiDB User Group

Discussion