diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b42da5159bc..f3a78730273 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5635,6 +5635,15 @@ best_access_path(JOIN *join, } +/* + Find JOIN_TAB's embedding (i.e, parent) subquery. + - For merged semi-joins, tables inside the semi-join nest have their + semi-join nest as parent. We intentionally ignore results of table + pullout action here. + - For non-merged semi-joins (JTBM tabs), the embedding subquery is the + JTBM join tab itself. +*/ + static TABLE_LIST* get_emb_subq(JOIN_TAB *tab) { TABLE_LIST *tlist= tab->table->pos_in_table_list; @@ -5648,8 +5657,21 @@ static TABLE_LIST* get_emb_subq(JOIN_TAB *tab) /* + Choose initial table order that "helps" semi-join optimizations. + + The idea is that we should start with the order that is the same as the one + we would have had if we had semijoin=off: + - Top-level tables go first + - subquery tables are grouped together by the subquery they are in, + - subquery tables are attached where the subquery predicate would have been + attached if we had semi-join off. + + This function relies on join_tab_cmp()/join_tab_cmp_straight() to produce + certain pre-liminary ordering, see compare_embedding_subqueries() for its + description. */ -static void pre_sort_tables(JOIN *join) + +static void choose_initial_table_order(JOIN *join) { TABLE_LIST *emb_subq; JOIN_TAB **tab= join->best_ref + join->const_tables; @@ -5660,10 +5682,12 @@ static void pre_sort_tables(JOIN *join) if ((emb_subq= get_emb_subq(*tab))) break; } - /* Copy the subquery JOIN_TABs to a separate array */ uint n_subquery_tabs= tabs_end - tab; + if (!n_subquery_tabs) return; + + /* Copy the subquery JOIN_TABs to a separate array */ JOIN_TAB *subquery_tabs[MAX_TABLES]; memcpy(subquery_tabs, tab, sizeof(JOIN_TAB*) * n_subquery_tabs); @@ -5787,7 +5811,7 @@ choose_plan(JOIN *join, table_map join_tables) if (!join->emb_sjm_nest) { - pre_sort_tables(join); + choose_initial_table_order(join); } join->cur_sj_inner_tables= 0; @@ -5828,6 +5852,18 @@ choose_plan(JOIN *join, table_map join_tables) } +/* + Compare two join tabs based on the subqueries they are from. + - top-level join tabs go first + - then subqueries are ordered by their select_id (we're using this + criteria because we need a cross-platform, deterministic ordering) + + @return + 0 - equal + -1 - jt1 < jt2 + 1 - jt1 > jt2 +*/ + static int compare_embedding_subqueries(JOIN_TAB *jt1, JOIN_TAB *jt2) { /* Determine if the first table is originally from a subquery */ @@ -5865,7 +5901,8 @@ static int compare_embedding_subqueries(JOIN_TAB *jt1, JOIN_TAB *jt2) /* Put top-level tables in front. Tables from within subqueries must follow, grouped by their owner subquery. We don't care about the order that - subquery groups are in, because pre_sort_tables() will move the groups. + subquery groups are in, because choose_initial_table_order() will re-order + the groups. */ if (tbl1_select_no != tbl2_select_no) return tbl1_select_no > tbl2_select_no ? 1 : -1; @@ -5889,6 +5926,9 @@ static int compare_embedding_subqueries(JOIN_TAB *jt1, JOIN_TAB *jt2) a: dependent = 0x0 table->map = 0x1 found_records = 3 ptr = 0x907e6b0 b: dependent = 0x0 table->map = 0x2 found_records = 3 ptr = 0x907e838 c: dependent = 0x6 table->map = 0x10 found_records = 2 ptr = 0x907ecd0 + + As for subuqueries, this function must produce order that can be fed to + choose_initial_table_order(). @retval 1 if first is bigger