diff --git a/mysql-test/main/opt_hints.result b/mysql-test/main/opt_hints.result index 2249e70567f..4aea5477737 100644 --- a/mysql-test/main/opt_hints.result +++ b/mysql-test/main/opt_hints.result @@ -1135,6 +1135,24 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 0 Using where; Using join buffer (flat, BNL join) 1 SIMPLE t3 ALL NULL NULL NULL NULL 0 Using where; Using join buffer (incremental, BNL join) 1 SIMPLE t4 ALL NULL NULL NULL NULL 0 Using where; Using join buffer (incremental, BNL join) +set join_cache_level=8; +INSERT INTO t2 VALUES (1), (2), (null), (1); +# BNLH buffer is used when allowed by JCL setting +EXPLAIN SELECT * FROM t1, t2 WHERE t1.a=t2.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where +1 SIMPLE t2 hash_ALL NULL #hash#$hj 5 test.t1.a 4 Using where; Using join buffer (flat, BNLH join) +# Make sure the hint enables BNL even when JCL=0: +set join_cache_level=0; +EXPLAIN SELECT /*+BNL(t2) */ * FROM t1, t2 WHERE t1.a=t2.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where +1 SIMPLE t2 hash_ALL NULL #hash#$hj 5 test.t1.a 4 Using where; Using join buffer (flat, BNLH join) +set join_cache_level=2; +EXPLAIN SELECT /*+BNL(t2) */ * FROM t1, t2 WHERE t1.a=t2.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where +1 SIMPLE t2 hash_ALL NULL #hash#$hj 5 test.t1.a 4 Using where; Using join buffer (flat, BNLH join) DROP TABLE t1,t2,t3,t4; # # Mix of BNL/BKA flat and incremental join buffers for OUTER JOINs diff --git a/mysql-test/main/opt_hints.test b/mysql-test/main/opt_hints.test index 755f5bce23b..67511292840 100644 --- a/mysql-test/main/opt_hints.test +++ b/mysql-test/main/opt_hints.test @@ -565,6 +565,18 @@ EXPLAIN SELECT /*+ BNL(t2, t3, t4)*/ t1.a FROM t1 LEFT JOIN (t2 LEFT JOIN (t3 LEFT JOIN t4 ON 1) ON t2.a) ON 0 WHERE t1.a OR t4.a; +set join_cache_level=8; +INSERT INTO t2 VALUES (1), (2), (null), (1); +--echo # BNLH buffer is used when allowed by JCL setting +EXPLAIN SELECT * FROM t1, t2 WHERE t1.a=t2.a; + +--echo # Make sure the hint enables BNL even when JCL=0: +set join_cache_level=0; +EXPLAIN SELECT /*+BNL(t2) */ * FROM t1, t2 WHERE t1.a=t2.a; + +set join_cache_level=2; +EXPLAIN SELECT /*+BNL(t2) */ * FROM t1, t2 WHERE t1.a=t2.a; + DROP TABLE t1,t2,t3,t4; diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc index 9f4875c2229..09dab83439b 100644 --- a/sql/multi_range_read.cc +++ b/sql/multi_range_read.cc @@ -1908,7 +1908,7 @@ bool DsMrr_impl::choose_mrr_impl(uint keyno, ha_rows rows, uint *flags, OPTIMIZER_SWITCH_MRR); const bool force_dsmrr_by_hints= hint_key_state(thd, table, keyno, MRR_HINT_ENUM, 0) || - hint_table_state(thd, table, BKA_HINT_ENUM, 0); + hint_table_state(thd, table, BKA_HINT_ENUM, false); bool doing_cpk_scan= check_cpk_scan(thd, share, keyno, *flags); bool using_cpk= primary_file->is_clustering_key(keyno); diff --git a/sql/opt_hints.cc b/sql/opt_hints.cc index 727fc7aa242..fb50621ca82 100644 --- a/sql/opt_hints.cc +++ b/sql/opt_hints.cc @@ -483,24 +483,6 @@ bool hint_key_state(const THD *thd, const TABLE *table, bool hint_table_state(const THD *thd, const TABLE *table, - opt_hints_enum type_arg, - uint optimizer_switch) -{ - TABLE_LIST *table_list= table->pos_in_table_list; - if (table_list->opt_hints_qb) - { - bool ret_val= false; - if (get_hint_state(table_list->opt_hints_table, - table_list->opt_hints_qb, - type_arg, &ret_val)) - return ret_val; - } - - return optimizer_flag(thd, optimizer_switch); -} - - -bool hint_table_state_or_fallback(const THD *thd, const TABLE *table, opt_hints_enum type_arg, bool fallback_value) { diff --git a/sql/opt_hints.h b/sql/opt_hints.h index 1b95b5a7269..fec5fc25c2f 100644 --- a/sql/opt_hints.h +++ b/sql/opt_hints.h @@ -543,21 +543,6 @@ bool hint_key_state(const THD *thd, const TABLE *table, uint keyno, opt_hints_enum type_arg, uint optimizer_switch); -/** - Returns table hint value if hint is specified, returns - optimizer switch value if hint is not specified. - - @param thd Pointer to THD object - @param tab Pointer to TABLE object - @param type_arg Hint type - @param optimizer_switch Optimizer switch flag - - @return table hint value if hint is specified, - otherwise optimizer switch value. -*/ -bool hint_table_state(const THD *thd, const TABLE *table, - opt_hints_enum type_arg, - uint optimizer_switch); /** Returns table hint value if hint is specified, returns @@ -571,7 +556,6 @@ bool hint_table_state(const THD *thd, const TABLE *table, @return table hint value if hint is specified, otherwise fallback value. */ -bool hint_table_state_or_fallback(const THD *thd, const TABLE *table, - opt_hints_enum type_arg, - bool fallback_value); +bool hint_table_state(const THD *thd, const TABLE *table, + opt_hints_enum type_arg, bool fallback_value); #endif /* OPT_HINTS_INCLUDED */ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 6e1168368aa..d2fa54a429c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -6662,7 +6662,7 @@ add_key_field(JOIN *join, { uint optimize= 0; if (eq_func && - ((join->is_allowed_hash_join_access() && + ((join->is_allowed_hash_join_access(field->table) && field->hash_join_is_possible() && !(field->table->pos_in_table_list->is_materialized_derived() && field->table->is_created())) || @@ -9428,8 +9428,7 @@ best_access_path(JOIN *join, (2) s is inner table of outer join -> join cache is allowed for outer joins */ if (idx > join->const_tables && best.key == 0 && - (join->allowed_join_cache_types & JOIN_CACHE_HASHED_BIT) && - join->max_allowed_join_cache_level > 2 && + join->is_allowed_hash_join_access(table) && !bitmap_is_clear_all(eq_join_set) && !disable_jbuf && (!s->emb_sj_nest || join->allowed_semijoin_with_cache) && // (1) @@ -11468,7 +11467,6 @@ get_costs_for_tables(JOIN *join, table_map remaining_tables, uint idx, JOIN_TAB *s; table_map found_tables= 0; bool found_eq_ref= 0; - bool disable_jbuf= join->thd->variables.join_cache_level == 0; DBUG_ENTER("get_plans_for_tables"); s= *pos; @@ -11485,6 +11483,11 @@ get_costs_for_tables(JOIN *join, table_map remaining_tables, uint idx, sort_end->join_tab= pos; sort_end->position= sort_position; + bool hint_forces_jbuf= + hint_table_state(join->thd, s->table, BNL_HINT_ENUM, false); + + bool disable_jbuf= + (join->thd->variables.join_cache_level == 0) && !hint_forces_jbuf; Json_writer_object wrapper(thd); /* Find the best access method from 's' to the current partial plan */ @@ -14471,11 +14474,17 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) add_cond_and_fix(thd, &tmp, tab->select_cond); } + uint max_jcl= join->max_allowed_join_cache_level; + bool is_hash_allowed= join->allowed_join_cache_types & + JOIN_CACHE_HASHED_BIT; + bool is_bnlh_enabled= ((max_jcl == 3 || max_jcl == 4) && + is_hash_allowed) || + hint_table_state(thd, tab->table, BNL_HINT_ENUM, false); + bool is_bkah_enabled= (max_jcl > 4 && is_hash_allowed) || + hint_table_state(thd, tab->table, BKA_HINT_ENUM, false); is_hj= (tab->type == JT_REF || tab->type == JT_EQ_REF) && - (join->allowed_join_cache_types & JOIN_CACHE_HASHED_BIT) && - ((join->max_allowed_join_cache_level+1)/2 == 2 || - ((join->max_allowed_join_cache_level+1)/2 > 2 && - is_hash_join_key_no(tab->ref.key))) && + (is_bnlh_enabled || + (is_bkah_enabled && is_hash_join_key_no(tab->ref.key))) && (!tab->emb_sj_nest || join->allowed_semijoin_with_cache) && (!(tab->table->map & join->outer_join) || @@ -15631,17 +15640,14 @@ end_sj_materialize(JOIN *join, JOIN_TAB *join_tab, bool end_of_records) OPTIMIZER_HINTS The following hints may influence the choice of join buffering: BNL(t1,t2,..): enables BNL and BNLH buffers for the specified tables - when join_cache_level=0. Effectively it increases + when join_cache_level < 4. It effectively increases join_cache_level to 4 for given tables. NO_BNL(t1,t2,..): disables BNL/BNLH join buffers, which could have been chosen for the specified tables otherwise. Does not prevent employing of BKA/BKAH buffers BKA(t1,t2,..): enables BKA and BKAH buffers for the specified tables - when optimizer switch join_cache_bka=off. Does not - increase join_cache_level, i.e., when join_cache_level=4 - and the hint is specified, BKA join buffers will still - not be employed. The hint effectively overrides only - optimizer switch join_cache_bka setting. + when join_cache_level < 5 and/or + optimizer switch join_cache_bka=off. NO_BKA(t1,t2,..): disables BKA/BKAH join buffers, which could have been chosen for the specified tables otherwise. However, does not prevent employing of BNL/BNLH buffers. @@ -15710,22 +15716,19 @@ uint check_join_cache_usage(JOIN_TAB *tab, !(join->allowed_join_cache_types & JOIN_CACHE_INCREMENTAL_BIT); bool no_hashed_cache= !(join->allowed_join_cache_types & JOIN_CACHE_HASHED_BIT); - bool no_bnl_cache= !hint_table_state_or_fallback(join->thd, - tab->tab_list->table, BNL_HINT_ENUM, true); - bool no_bka_cache= !hint_table_state_or_fallback(join->thd, - tab->tab_list->table, BKA_HINT_ENUM, - join->allowed_join_cache_types & JOIN_CACHE_BKA_BIT); - bool hint_forces_bka= hint_table_state_or_fallback(join->thd, - tab->tab_list->table, - BKA_HINT_ENUM, false); + bool no_bnl_cache= !hint_table_state(join->thd, tab->tab_list->table, + BNL_HINT_ENUM, true); + bool no_bka_cache= !hint_table_state(join->thd, tab->tab_list->table, + BKA_HINT_ENUM, join->allowed_join_cache_types & JOIN_CACHE_BKA_BIT); + bool hint_forces_bka= hint_table_state(join->thd, tab->tab_list->table, + BKA_HINT_ENUM, false); join->return_tab= 0; if (tab->no_forced_join_cache || (no_bnl_cache && no_bka_cache)) goto no_join_cache; - if (cache_level < 4 && hint_table_state_or_fallback(join->thd, - tab->tab_list->table, - BNL_HINT_ENUM, false)) + if (cache_level < 4 && hint_table_state(join->thd, tab->tab_list->table, + BNL_HINT_ENUM, false)) { cache_level= 4; // BNL() hint present, raise join_cache_level to BNLH } @@ -32445,6 +32448,13 @@ void JOIN::set_allowed_join_cache_types() max_allowed_join_cache_level= thd->variables.join_cache_level; } +bool JOIN::is_allowed_hash_join_access(const TABLE *table) +{ + return allowed_join_cache_types & JOIN_CACHE_HASHED_BIT && + (max_allowed_join_cache_level > JOIN_CACHE_HASHED_BIT || + hint_table_state(thd, table, BNL_HINT_ENUM, false) || + hint_table_state(thd, table, BKA_HINT_ENUM, false)); +} /** Save a query execution plan so that the caller can revert to it if needed, diff --git a/sql/sql_select.h b/sql/sql_select.h index 7b1700b8293..25d8cdaafed 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1885,11 +1885,7 @@ public: ulonglong curr_space, ulonglong needed_space); void set_allowed_join_cache_types(); - bool is_allowed_hash_join_access() - { - return MY_TEST(allowed_join_cache_types & JOIN_CACHE_HASHED_BIT) && - max_allowed_join_cache_level > JOIN_CACHE_HASHED_BIT; - } + bool is_allowed_hash_join_access(const TABLE *table); /* Check if we need to create a temporary table. This has to be done if all tables are not already read (const tables)