Skip to content

Commit caa8f24

Browse files
author
Steinar H. Gunderson
committed
WL #14071: Hypergraph join optimizer base [patch 10/10, fix block crossing]
Fix an issue where WalkAccessPaths() would not properly cross STREAM and MATERIALIZE nodes within the same query block -- it would assume they were always part of a different query block. Change-Id: I85b358de9bcbc833cf4724d28275e7622d180f1f
1 parent bc00c07 commit caa8f24

File tree

4 files changed

+53
-38
lines changed

4 files changed

+53
-38
lines changed

sql/join_optimizer/access_path.cc

+13-7
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,10 @@ static AccessPath *FindSingleAccessPathOfType(AccessPath *path,
8787
}
8888
return false;
8989
};
90-
WalkAccessPaths(path, /*cross_query_blocks=*/false, func);
90+
// Our users generally want to stop at STREAM or MATERIALIZE nodes,
91+
// since they are table-oriented and those nodes have their own tables.
92+
// join == nullptr achieves that.
93+
WalkAccessPaths(path, /*join=*/nullptr, /*cross_query_blocks=*/false, func);
9194
return found_path;
9295
}
9396

@@ -740,29 +743,32 @@ void FindTablesToGetRowidFor(AccessPath *path) {
740743
}
741744
};
742745

746+
// We use join == nullptr, so that we stop at MATERIALIZE and STREAM
747+
// (they supply row IDs for us without having to ask the tables below).
743748
switch (path->type) {
744749
case AccessPath::HASH_JOIN:
745-
WalkAccessPaths(path, /*cross_query_blocks=*/false,
750+
WalkAccessPaths(path, /*join=*/nullptr, /*cross_query_blocks=*/false,
746751
add_tables_handled_by_others);
747752
path->hash_join().store_rowids = true;
748753
path->hash_join().tables_to_get_rowid_for =
749754
GetUsedTables(path) & ~handled_by_others;
750755
break;
751756
case AccessPath::BKA_JOIN:
752-
WalkAccessPaths(path->bka_join().outer, /*cross_query_blocks=*/false,
757+
WalkAccessPaths(path->bka_join().outer, /*join=*/nullptr,
758+
/*cross_query_blocks=*/false,
753759
add_tables_handled_by_others);
754760
path->bka_join().store_rowids = true;
755761
path->bka_join().tables_to_get_rowid_for =
756762
GetUsedTables(path->bka_join().outer) & ~handled_by_others;
757763
break;
758764
case AccessPath::WEEDOUT:
759-
WalkAccessPaths(path, /*cross_query_blocks=*/false,
765+
WalkAccessPaths(path, /*join=*/nullptr, /*cross_query_blocks=*/false,
760766
add_tables_handled_by_others);
761767
path->weedout().tables_to_get_rowid_for =
762768
GetUsedTables(path) & ~handled_by_others;
763769
break;
764770
case AccessPath::SORT:
765-
WalkAccessPaths(path, /*cross_query_blocks=*/false,
771+
WalkAccessPaths(path, /*join=*/nullptr, /*cross_query_blocks=*/false,
766772
add_tables_handled_by_others);
767773
path->sort().tables_to_get_rowid_for =
768774
GetUsedTables(path) & ~handled_by_others;
@@ -789,10 +795,10 @@ static Item *ConditionFromFilterPredicates(
789795
}
790796
}
791797

792-
void ExpandFilterAccessPaths(THD *thd, AccessPath *path_arg,
798+
void ExpandFilterAccessPaths(THD *thd, AccessPath *path_arg, const JOIN *join,
793799
const Mem_root_array<Predicate> &predicates) {
794800
WalkAccessPaths(
795-
path_arg, /*cross_query_blocks=*/false,
801+
path_arg, join, /*cross_query_blocks=*/false,
796802
[thd, &predicates](AccessPath *path) {
797803
if (path->filter_predicates != 0) {
798804
Item *condition = ConditionFromFilterPredicates(

sql/join_optimizer/access_path.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -1210,8 +1210,10 @@ table_map GetUsedTables(const AccessPath *path);
12101210
predicate list. This is used after finding an optimal set of access paths,
12111211
to normalize the tree so that the remaining consumers do not need to worry
12121212
about filter_predicates and cost_before_filter.
1213+
1214+
“join” is the join that “path” is part of.
12131215
*/
1214-
void ExpandFilterAccessPaths(THD *thd, AccessPath *path,
1216+
void ExpandFilterAccessPaths(THD *thd, AccessPath *path, const JOIN *join,
12151217
const Mem_root_array<Predicate> &predicates);
12161218

12171219
#endif // SQL_JOIN_OPTIMIZER_ACCESS_PATH_H

sql/join_optimizer/join_optimizer.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,7 @@ AccessPath *FindBestQueryPlan(THD *thd, SELECT_LEX *select_lex, string *trace) {
716716

717717
// Now that we have decided on a full plan, expand all the applied
718718
// filter maps into proper FILTER nodes for execution.
719-
ExpandFilterAccessPaths(thd, root_path, graph.predicates);
719+
ExpandFilterAccessPaths(thd, root_path, join, graph.predicates);
720720

721721
// Apply GROUP BY, if applicable. We currently always do this by sorting
722722
// first and then using streaming aggregation.

sql/join_optimizer/walk_access_paths.h

+36-29
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,18 @@
3030
if cross_query_blocks is false), calling func() for each one with pre-
3131
or post-order traversal. If func() returns true, traversal is stopped early.
3232
33+
The `join` parameter, signifying what query block `path` is part of, is only
34+
used if you set cross_query_blocks = false. It is used to know whether a
35+
MATERIALIZE or STREAM access path is part of the same query block or not.
36+
If you give join == nullptr and cross_query_blocks == false, the walk will
37+
always stop at such access paths.
38+
3339
Nothing currently uses post-order traversal, but it has been requested for
3440
future use.
3541
*/
3642
template <class Func>
37-
void WalkAccessPaths(AccessPath *path, bool cross_query_blocks, Func &&func,
43+
void WalkAccessPaths(AccessPath *path, const JOIN *join,
44+
bool cross_query_blocks, Func &&func,
3845
bool post_order_traversal = false) {
3946
if (!post_order_traversal) {
4047
if (func(path)) {
@@ -64,103 +71,103 @@ void WalkAccessPaths(AccessPath *path, bool cross_query_blocks, Func &&func,
6471
// No children.
6572
return;
6673
case AccessPath::NESTED_LOOP_JOIN:
67-
WalkAccessPaths(path->nested_loop_join().outer, cross_query_blocks,
74+
WalkAccessPaths(path->nested_loop_join().outer, join, cross_query_blocks,
6875
std::forward<Func &&>(func), post_order_traversal);
69-
WalkAccessPaths(path->nested_loop_join().inner, cross_query_blocks,
76+
WalkAccessPaths(path->nested_loop_join().inner, join, cross_query_blocks,
7077
std::forward<Func &&>(func), post_order_traversal);
7178
break;
7279
case AccessPath::NESTED_LOOP_SEMIJOIN_WITH_DUPLICATE_REMOVAL:
7380
WalkAccessPaths(path->nested_loop_semijoin_with_duplicate_removal().outer,
74-
cross_query_blocks, std::forward<Func &&>(func),
81+
join, cross_query_blocks, std::forward<Func &&>(func),
7582
post_order_traversal);
7683
WalkAccessPaths(path->nested_loop_semijoin_with_duplicate_removal().inner,
77-
cross_query_blocks, std::forward<Func &&>(func),
84+
join, cross_query_blocks, std::forward<Func &&>(func),
7885
post_order_traversal);
7986
break;
8087
case AccessPath::BKA_JOIN:
81-
WalkAccessPaths(path->bka_join().outer, cross_query_blocks,
88+
WalkAccessPaths(path->bka_join().outer, join, cross_query_blocks,
8289
std::forward<Func &&>(func), post_order_traversal);
83-
WalkAccessPaths(path->bka_join().inner, cross_query_blocks,
90+
WalkAccessPaths(path->bka_join().inner, join, cross_query_blocks,
8491
std::forward<Func &&>(func), post_order_traversal);
8592
break;
8693
case AccessPath::HASH_JOIN:
87-
WalkAccessPaths(path->hash_join().outer, cross_query_blocks,
94+
WalkAccessPaths(path->hash_join().outer, join, cross_query_blocks,
8895
std::forward<Func &&>(func), post_order_traversal);
89-
WalkAccessPaths(path->hash_join().inner, cross_query_blocks,
96+
WalkAccessPaths(path->hash_join().inner, join, cross_query_blocks,
9097
std::forward<Func &&>(func), post_order_traversal);
9198
break;
9299
case AccessPath::FILTER:
93-
WalkAccessPaths(path->filter().child, cross_query_blocks,
100+
WalkAccessPaths(path->filter().child, join, cross_query_blocks,
94101
std::forward<Func &&>(func), post_order_traversal);
95102
break;
96103
case AccessPath::SORT:
97-
WalkAccessPaths(path->sort().child, cross_query_blocks,
104+
WalkAccessPaths(path->sort().child, join, cross_query_blocks,
98105
std::forward<Func &&>(func), post_order_traversal);
99106
break;
100107
case AccessPath::AGGREGATE:
101-
WalkAccessPaths(path->aggregate().child, cross_query_blocks,
108+
WalkAccessPaths(path->aggregate().child, join, cross_query_blocks,
102109
std::forward<Func &&>(func), post_order_traversal);
103110
break;
104111
case AccessPath::TEMPTABLE_AGGREGATE:
105-
WalkAccessPaths(path->temptable_aggregate().subquery_path,
112+
WalkAccessPaths(path->temptable_aggregate().subquery_path, join,
106113
cross_query_blocks, std::forward<Func &&>(func),
107114
post_order_traversal);
108-
WalkAccessPaths(path->temptable_aggregate().table_path,
115+
WalkAccessPaths(path->temptable_aggregate().table_path, join,
109116
cross_query_blocks, std::forward<Func &&>(func),
110117
post_order_traversal);
111118
break;
112119
case AccessPath::LIMIT_OFFSET:
113-
WalkAccessPaths(path->limit_offset().child, cross_query_blocks,
120+
WalkAccessPaths(path->limit_offset().child, join, cross_query_blocks,
114121
std::forward<Func &&>(func), post_order_traversal);
115122
break;
116123
case AccessPath::STREAM:
117-
if (cross_query_blocks) {
118-
WalkAccessPaths(path->stream().child, cross_query_blocks,
124+
if (cross_query_blocks || path->stream().join == join) {
125+
WalkAccessPaths(path->stream().child, join, cross_query_blocks,
119126
std::forward<Func &&>(func), post_order_traversal);
120127
}
121128
break;
122129
case AccessPath::MATERIALIZE:
123-
WalkAccessPaths(path->materialize().table_path, cross_query_blocks,
130+
WalkAccessPaths(path->materialize().table_path, join, cross_query_blocks,
124131
std::forward<Func &&>(func), post_order_traversal);
125-
if (cross_query_blocks) {
126-
for (const MaterializePathParameters::QueryBlock &query_block :
127-
path->materialize().param->query_blocks) {
128-
WalkAccessPaths(query_block.subquery_path, cross_query_blocks,
132+
for (const MaterializePathParameters::QueryBlock &query_block :
133+
path->materialize().param->query_blocks) {
134+
if (cross_query_blocks || query_block.join == join) {
135+
WalkAccessPaths(query_block.subquery_path, join, cross_query_blocks,
129136
std::forward<Func &&>(func), post_order_traversal);
130137
}
131138
}
132139
break;
133140
case AccessPath::MATERIALIZE_INFORMATION_SCHEMA_TABLE:
134141
WalkAccessPaths(path->materialize_information_schema_table().table_path,
135-
cross_query_blocks, std::forward<Func &&>(func),
142+
join, cross_query_blocks, std::forward<Func &&>(func),
136143
post_order_traversal);
137144
break;
138145
case AccessPath::APPEND:
139146
if (cross_query_blocks) {
140147
for (const AppendPathParameters &child : *path->append().children) {
141-
WalkAccessPaths(child.path, cross_query_blocks,
148+
WalkAccessPaths(child.path, join, cross_query_blocks,
142149
std::forward<Func &&>(func), post_order_traversal);
143150
}
144151
}
145152
break;
146153
case AccessPath::WINDOWING:
147-
WalkAccessPaths(path->windowing().child, cross_query_blocks,
154+
WalkAccessPaths(path->windowing().child, join, cross_query_blocks,
148155
std::forward<Func &&>(func), post_order_traversal);
149156
break;
150157
case AccessPath::WEEDOUT:
151-
WalkAccessPaths(path->weedout().child, cross_query_blocks,
158+
WalkAccessPaths(path->weedout().child, join, cross_query_blocks,
152159
std::forward<Func &&>(func), post_order_traversal);
153160
break;
154161
case AccessPath::REMOVE_DUPLICATES:
155-
WalkAccessPaths(path->remove_duplicates().child, cross_query_blocks,
162+
WalkAccessPaths(path->remove_duplicates().child, join, cross_query_blocks,
156163
std::forward<Func &&>(func), post_order_traversal);
157164
break;
158165
case AccessPath::ALTERNATIVE:
159-
WalkAccessPaths(path->alternative().child, cross_query_blocks,
166+
WalkAccessPaths(path->alternative().child, join, cross_query_blocks,
160167
std::forward<Func &&>(func), post_order_traversal);
161168
break;
162169
case AccessPath::CACHE_INVALIDATOR:
163-
WalkAccessPaths(path->cache_invalidator().child, cross_query_blocks,
170+
WalkAccessPaths(path->cache_invalidator().child, join, cross_query_blocks,
164171
std::forward<Func &&>(func), post_order_traversal);
165172
break;
166173
}

0 commit comments

Comments
 (0)