Minor cleanup in the optimizer trace code.

More test coverage added for the optimizer trace.
This commit is contained in:
Varun Gupta 2019-02-18 17:11:20 +05:30
parent 7d2138d4a4
commit 9cb55143ac
17 changed files with 3037 additions and 469 deletions

File diff suppressed because it is too large Load Diff

View File

@ -323,6 +323,7 @@ set optimizer_trace='enabled=off';
--echo # MDEV-18528: Optimizer trace support for multi-table UPDATE and DELETE --echo # MDEV-18528: Optimizer trace support for multi-table UPDATE and DELETE
--echo # --echo #
set optimizer_trace=1;
create table ten(a int); create table ten(a int);
insert into ten values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); insert into ten values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t0 (a int, b int); create table t0 (a int, b int);
@ -333,3 +334,43 @@ insert into t1 select * from t0;
explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3; explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3;
select * from information_schema.optimizer_trace; select * from information_schema.optimizer_trace;
drop table ten,t0,t1; drop table ten,t0,t1;
set optimizer_trace='enabled=off';
--echo #
--echo # Merged to Materialized for derived tables
--echo #
set optimizer_trace=1;
create table t1 (a int);
insert into t1 values (1),(2),(3);
explain select * from (select rand() from t1)q;
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
drop table t1;
set optimizer_trace='enabled=off';
--echo #
--echo # Semi-join nest
--echo #
set optimizer_trace=1;
create table t1 (a int);
insert into t1 values (1),(2),(3);
create table t2(a int);
insert into t2 values (1),(2),(3),(1),(2),(3),(1),(2),(3);
set @save_optimizer_switch= @@optimizer_switch;
explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_inner_2);
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
--echo # with Firstmatch, mostly for tracing fix_semijoin_strategies_for_picked_join_order
set optimizer_switch='materialization=off';
explain select * from t1 t_outer_1,t2 t_outer_2 where t_outer_1.a in (select t_inner_1.a from t2 t_inner_2, t1 t_inner_1) and
t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4);
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
set optimizer_switch='materialization=on';
explain select * from t1 t_outer_1,t2 t_outer_2 where t_outer_1.a in (select t_inner_1.a from t2 t_inner_2, t1 t_inner_1) and
t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4);
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
set @@optimizer_switch= @save_optimizer_switch;
drop table t1,t2;
set optimizer_trace='enabled=off';

View File

@ -24,7 +24,7 @@ explain select * from t1 where a=1 or b=1 {
"select_id": 1, "select_id": 1,
"steps": [ "steps": [
{ {
"expanded_query": "select `t1`.`a` AS `a`,`t1`.`b` AS `b`,`t1`.`c` AS `c`,`t1`.`filler` AS `filler` from `t1` where `t1`.`a` = 1 or `t1`.`b` = 1" "expanded_query": "select t1.a AS a,t1.b AS b,t1.c AS c,t1.filler AS filler from t1 where t1.a = 1 or t1.b = 1"
} }
] ]
} }
@ -194,15 +194,11 @@ explain select * from t1 where a=1 or b=1 {
}, },
{ {
"selectivity_for_indexes": [], "selectivity_for_indexes": [],
"selectivity_for_columns": [] "selectivity_for_columns": [],
"cond_selectivity": 0.002
} }
] ]
}, },
{
"execution_plan_for_potential_materialization": {
"steps": []
}
},
{ {
"considered_execution_plans": [ "considered_execution_plans": [
{ {

View File

@ -32,7 +32,7 @@ explain select * from t1 where pk1 != 0 and key1 = 1 {
"select_id": 1, "select_id": 1,
"steps": [ "steps": [
{ {
"expanded_query": "select `t1`.`pk1` AS `pk1`,`t1`.`pk2` AS `pk2`,`t1`.`key1` AS `key1`,`t1`.`key2` AS `key2` from `t1` where `t1`.`pk1` <> 0 and `t1`.`key1` = 1" "expanded_query": "select t1.pk1 AS pk1,t1.pk2 AS pk2,t1.key1 AS key1,t1.key2 AS key2 from t1 where t1.pk1 <> 0 and t1.key1 = 1"
} }
] ]
} }
@ -183,15 +183,11 @@ explain select * from t1 where pk1 != 0 and key1 = 1 {
"selectivity_from_index": 0.001 "selectivity_from_index": 0.001
} }
], ],
"selectivity_for_columns": [] "selectivity_for_columns": [],
"cond_selectivity": 0.001
} }
] ]
}, },
{
"execution_plan_for_potential_materialization": {
"steps": []
}
},
{ {
"considered_execution_plans": [ "considered_execution_plans": [
{ {

View File

@ -55,7 +55,7 @@ select * from db1.t1 {
"select_id": 1, "select_id": 1,
"steps": [ "steps": [
{ {
"expanded_query": "select `db1`.`t1`.`a` AS `a` from `t1`" "expanded_query": "select db1.t1.a AS a from t1"
} }
] ]
} }
@ -85,11 +85,6 @@ select * from db1.t1 {
} }
] ]
}, },
{
"execution_plan_for_potential_materialization": {
"steps": []
}
},
{ {
"considered_execution_plans": [ "considered_execution_plans": [
{ {
@ -157,7 +152,7 @@ select * from db1.v1 {
"view": { "view": {
"table": "v1", "table": "v1",
"select_id": 2, "select_id": 2,
"merged": true "algorithm": "merged"
} }
}, },
{ {
@ -165,13 +160,13 @@ select * from db1.v1 {
"select_id": 2, "select_id": 2,
"steps": [ "steps": [
{ {
"expanded_query": "/* select#2 */ select `db1`.`t1`.`a` AS `a` from `t1`" "expanded_query": "/* select#2 */ select db1.t1.a AS a from t1"
} }
] ]
} }
}, },
{ {
"expanded_query": "/* select#1 */ select `db1`.`t1`.`a` AS `a` from `v1`" "expanded_query": "/* select#1 */ select db1.t1.a AS a from v1"
} }
] ]
} }
@ -201,11 +196,6 @@ select * from db1.v1 {
} }
] ]
}, },
{
"execution_plan_for_potential_materialization": {
"steps": []
}
},
{ {
"considered_execution_plans": [ "considered_execution_plans": [
{ {

View File

@ -226,8 +226,8 @@ Json_writer_object::Json_writer_object(THD *thd) :
my_writer->start_object(); my_writer->start_object();
} }
Json_writer_object::Json_writer_object(THD* thd, const char *str) Json_writer_object::Json_writer_object(THD* thd, const char *str) :
: Json_writer_struct(thd) Json_writer_struct(thd)
{ {
if (my_writer) if (my_writer)
my_writer->add_member(str).start_object(); my_writer->add_member(str).start_object();
@ -247,8 +247,8 @@ Json_writer_array::Json_writer_array(THD *thd) :
my_writer->start_array(); my_writer->start_array();
} }
Json_writer_array::Json_writer_array(THD *thd, const char *str) Json_writer_array::Json_writer_array(THD *thd, const char *str) :
:Json_writer_struct(thd) Json_writer_struct(thd)
{ {
if (my_writer) if (my_writer)
my_writer->add_member(str).start_array(); my_writer->add_member(str).start_array();
@ -263,6 +263,16 @@ Json_writer_array::~Json_writer_array()
} }
} }
Json_writer_temp_disable::Json_writer_temp_disable(THD *thd_arg)
{
thd= thd_arg;
thd->opt_trace.disable_tracing_if_required();
}
Json_writer_temp_disable::~Json_writer_temp_disable()
{
thd->opt_trace.enable_tracing_if_required();
}
bool Single_line_formatting_helper::on_add_member(const char *name) bool Single_line_formatting_helper::on_add_member(const char *name)
{ {
DBUG_ASSERT(state== INACTIVE || state == DISABLED); DBUG_ASSERT(state== INACTIVE || state == DISABLED);

View File

@ -215,12 +215,11 @@ public:
*/ */
void set_size_limit(size_t mem_size) { output.set_size_limit(mem_size); } void set_size_limit(size_t mem_size) { output.set_size_limit(mem_size); }
// psergey: return how many bytes would be required to store everything
size_t get_truncated_bytes() { return output.get_truncated_bytes(); } size_t get_truncated_bytes() { return output.get_truncated_bytes(); }
Json_writer() : Json_writer() :
indent_level(0), document_start(true), element_started(false), indent_level(0), document_start(true), element_started(false),
first_child(true), allowed_mem_size(0) first_child(true)
{ {
fmt_helper.init(this); fmt_helper.init(this);
} }
@ -235,12 +234,6 @@ private:
bool element_started; bool element_started;
bool first_child; bool first_child;
/*
True when we are using the optimizer trace
FALSE otherwise
*/
size_t allowed_mem_size;
Single_line_formatting_helper fmt_helper; Single_line_formatting_helper fmt_helper;
void append_indent(); void append_indent();
@ -566,6 +559,17 @@ public:
~Json_writer_array(); ~Json_writer_array();
}; };
/*
RAII-based class to disable writing into the JSON document
*/
class Json_writer_temp_disable
{
public:
Json_writer_temp_disable(THD *thd_arg);
~Json_writer_temp_disable();
THD *thd;
};
/* /*
RAII-based helper class to detect incorrect use of Json_writer. RAII-based helper class to detect incorrect use of Json_writer.

View File

@ -2466,9 +2466,9 @@ void TRP_GROUP_MIN_MAX::trace_basic_info(const PARAM *param,
trace_object->add("type", "index_group").add("index", index_info->name); trace_object->add("type", "index_group").add("index", index_info->name);
if (min_max_arg_part) if (min_max_arg_part)
trace_object->add("group_attribute", min_max_arg_part->field->field_name); trace_object->add("min_max_arg", min_max_arg_part->field->field_name);
else else
trace_object->add_null("group_attribute"); trace_object->add_null("min_max_arg");
trace_object->add("min_aggregate", have_min) trace_object->add("min_aggregate", have_min)
.add("max_aggregate", have_max) .add("max_aggregate", have_max)
@ -3438,7 +3438,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond)
{ {
rows= 0; rows= 0;
table->reginfo.impossible_range= 1; table->reginfo.impossible_range= 1;
selectivity_for_column.add("selectivity_from_histograms", rows); selectivity_for_column.add("selectivity_from_histogram", rows);
selectivity_for_column.add("cause", "impossible range"); selectivity_for_column.add("cause", "impossible range");
goto free_alloc; goto free_alloc;
} }
@ -3448,7 +3448,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond)
if (rows != DBL_MAX) if (rows != DBL_MAX)
{ {
key->field->cond_selectivity= rows/table_records; key->field->cond_selectivity= rows/table_records;
selectivity_for_column.add("selectivity_from_histograms", selectivity_for_column.add("selectivity_from_histogram",
key->field->cond_selectivity); key->field->cond_selectivity);
} }
} }
@ -3472,6 +3472,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond)
free_root(&alloc, MYF(0)); free_root(&alloc, MYF(0));
} }
selectivity_for_columns.end();
if (quick && (quick->get_type() == QUICK_SELECT_I::QS_TYPE_ROR_UNION || if (quick && (quick->get_type() == QUICK_SELECT_I::QS_TYPE_ROR_UNION ||
quick->get_type() == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)) quick->get_type() == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE))
@ -3546,7 +3547,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond)
table->cond_selectivity_sampling_explain= &dt->list; table->cond_selectivity_sampling_explain= &dt->list;
} }
} }
trace_wrapper.add("cond_selectivity", table->cond_selectivity);
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
@ -15829,7 +15830,8 @@ static void print_key_value(String *out, const KEY_PART_INFO *key_part,
{ {
Field *field= key_part->field; Field *field= key_part->field;
if (field->flags & BLOB_FLAG) { if (field->flags & BLOB_FLAG)
{
// Byte 0 of a nullable key is the null-byte. If set, key is NULL. // Byte 0 of a nullable key is the null-byte. If set, key is NULL.
if (field->real_maybe_null() && *key) if (field->real_maybe_null() && *key)
out->append(STRING_WITH_LEN("NULL")); out->append(STRING_WITH_LEN("NULL"));
@ -15849,7 +15851,8 @@ static void print_key_value(String *out, const KEY_PART_INFO *key_part,
Otherwise, print the key value starting immediately after the Otherwise, print the key value starting immediately after the
null-byte null-byte
*/ */
if (*key) { if (*key)
{
out->append(STRING_WITH_LEN("NULL")); out->append(STRING_WITH_LEN("NULL"));
return; return;
} }
@ -15862,9 +15865,11 @@ static void print_key_value(String *out, const KEY_PART_INFO *key_part,
optimizer trace expects. If the column is binary, the hex optimizer trace expects. If the column is binary, the hex
representation is printed to the trace instead. representation is printed to the trace instead.
*/ */
if (field->flags & BINARY_FLAG) { if (field->flags & BINARY_FLAG)
{
out->append("0x"); out->append("0x");
for (uint i = 0; i < store_length; i++) { for (uint i = 0; i < store_length; i++)
{
out->append(_dig_vec_lower[*(key + i) >> 4]); out->append(_dig_vec_lower[*(key + i) >> 4]);
out->append(_dig_vec_lower[*(key + i) & 0x0F]); out->append(_dig_vec_lower[*(key + i) & 0x0F]);
} }

View File

@ -456,6 +456,7 @@ void best_access_path(JOIN *join, JOIN_TAB *s,
table_map remaining_tables, uint idx, table_map remaining_tables, uint idx,
bool disable_jbuf, double record_count, bool disable_jbuf, double record_count,
POSITION *pos, POSITION *loose_scan_pos); POSITION *pos, POSITION *loose_scan_pos);
void trace_plan_prefix(JOIN *join, uint idx, table_map remaining_tables);
static Item *create_subq_in_equalities(THD *thd, SJ_MATERIALIZATION_INFO *sjm, static Item *create_subq_in_equalities(THD *thd, SJ_MATERIALIZATION_INFO *sjm,
Item_in_subselect *subq_pred); Item_in_subselect *subq_pred);
@ -697,9 +698,10 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
if (arena) if (arena)
thd->restore_active_arena(arena, &backup); thd->restore_active_arena(arena, &backup);
in_subs->is_registered_semijoin= TRUE; in_subs->is_registered_semijoin= TRUE;
OPT_TRACE_TRANSFORM(thd, oto0, oto1, select_lex->select_number, OPT_TRACE_TRANSFORM(thd, trace_wrapper, trace_transform,
select_lex->select_number,
"IN (SELECT)", "semijoin"); "IN (SELECT)", "semijoin");
oto1.add("chosen", true); trace_transform.add("chosen", true);
} }
} }
else else
@ -840,7 +842,7 @@ bool subquery_types_allow_materialization(THD* thd, Item_in_subselect *in_subs)
in_subs->types_allow_materialization= FALSE; // Assign default values in_subs->types_allow_materialization= FALSE; // Assign default values
in_subs->sjm_scan_allowed= FALSE; in_subs->sjm_scan_allowed= FALSE;
OPT_TRACE_TRANSFORM(thd, oto0, oto1, OPT_TRACE_TRANSFORM(thd, trace_wrapper, trace_transform,
in_subs->get_select_lex()->select_number, in_subs->get_select_lex()->select_number,
"IN (SELECT)", "materialization"); "IN (SELECT)", "materialization");
@ -856,8 +858,8 @@ bool subquery_types_allow_materialization(THD* thd, Item_in_subselect *in_subs)
if (!inner->type_handler()->subquery_type_allows_materialization(inner, if (!inner->type_handler()->subquery_type_allows_materialization(inner,
outer)) outer))
{ {
oto1.add("possible", false); trace_transform.add("possible", false);
oto1.add("cause", "types mismatch"); trace_transform.add("cause", "types mismatch");
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
} }
@ -879,12 +881,12 @@ bool subquery_types_allow_materialization(THD* thd, Item_in_subselect *in_subs)
{ {
in_subs->types_allow_materialization= TRUE; in_subs->types_allow_materialization= TRUE;
in_subs->sjm_scan_allowed= all_are_fields; in_subs->sjm_scan_allowed= all_are_fields;
oto1.add("sjm_scan_allowed", all_are_fields) trace_transform.add("sjm_scan_allowed", all_are_fields)
.add("possible", true); .add("possible", true);
DBUG_PRINT("info",("subquery_types_allow_materialization: ok, allowed")); DBUG_PRINT("info",("subquery_types_allow_materialization: ok, allowed"));
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
oto1.add("possible", false).add("cause", cause); trace_transform.add("possible", false).add("cause", cause);
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
@ -1236,29 +1238,30 @@ bool convert_join_subqueries_to_semijoins(JOIN *join)
/* Stop processing if we've reached a subquery that's attached to the ON clause */ /* Stop processing if we've reached a subquery that's attached to the ON clause */
if (in_subq->do_not_convert_to_sj) if (in_subq->do_not_convert_to_sj)
{ {
OPT_TRACE_TRANSFORM(thd, oto0, oto1, OPT_TRACE_TRANSFORM(thd, trace_wrapper, trace_transform,
in_subq->get_select_lex()->select_number, in_subq->get_select_lex()->select_number,
"IN (SELECT)", "semijoin"); "IN (SELECT)", "semijoin");
oto1.add("converted_to_semi_join", false) trace_transform.add("converted_to_semi_join", false)
.add("cause", "subquery attached to the ON clause"); .add("cause", "subquery attached to the ON clause");
break; break;
} }
if (in_subq->is_flattenable_semijoin) if (in_subq->is_flattenable_semijoin)
{ {
OPT_TRACE_TRANSFORM(thd, oto0, oto1, OPT_TRACE_TRANSFORM(thd, trace_wrapper, trace_transform,
in_subq->get_select_lex()->select_number, in_subq->get_select_lex()->select_number,
"IN (SELECT)", "semijoin"); "IN (SELECT)", "semijoin");
if (join->table_count + if (join->table_count +
in_subq->unit->first_select()->join->table_count >= MAX_TABLES) in_subq->unit->first_select()->join->table_count >= MAX_TABLES)
{ {
oto1.add("converted_to_semi_join", false); trace_transform.add("converted_to_semi_join", false);
oto1.add("cause", "table in parent join now exceeds MAX_TABLES"); trace_transform.add("cause",
"table in parent join now exceeds MAX_TABLES");
break; break;
} }
if (convert_subq_to_sj(join, in_subq)) if (convert_subq_to_sj(join, in_subq))
goto restore_arena_and_fail; goto restore_arena_and_fail;
oto1.add("converted_to_semi_join", true); trace_transform.add("converted_to_semi_join", true);
} }
else else
{ {
@ -2380,6 +2383,8 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map)
THD *thd= join->thd; THD *thd= join->thd;
List_iterator<TABLE_LIST> sj_list_it(join->select_lex->sj_nests); List_iterator<TABLE_LIST> sj_list_it(join->select_lex->sj_nests);
TABLE_LIST *sj_nest; TABLE_LIST *sj_nest;
if (!join->select_lex->sj_nests.elements)
DBUG_RETURN(FALSE);
Json_writer_object wrapper(thd); Json_writer_object wrapper(thd);
Json_writer_object trace_semijoin_nest(thd, Json_writer_object trace_semijoin_nest(thd,
"execution_plan_for_potential_materialization"); "execution_plan_for_potential_materialization");
@ -2939,6 +2944,7 @@ bool Sj_materialization_picker::check_qep(JOIN *join,
{ {
bool sjm_scan; bool sjm_scan;
SJ_MATERIALIZATION_INFO *mat_info; SJ_MATERIALIZATION_INFO *mat_info;
THD *thd= join->thd;
if ((mat_info= at_sjmat_pos(join, remaining_tables, if ((mat_info= at_sjmat_pos(join, remaining_tables,
new_join_tab, idx, &sjm_scan))) new_join_tab, idx, &sjm_scan)))
{ {
@ -3040,6 +3046,7 @@ bool Sj_materialization_picker::check_qep(JOIN *join,
POSITION curpos, dummy; POSITION curpos, dummy;
/* Need to re-run best-access-path as we prefix_rec_count has changed */ /* Need to re-run best-access-path as we prefix_rec_count has changed */
bool disable_jbuf= (join->thd->variables.join_cache_level == 0); bool disable_jbuf= (join->thd->variables.join_cache_level == 0);
Json_writer_temp_disable trace_semijoin_mat_scan(thd);
for (i= first_tab + mat_info->tables; i <= idx; i++) for (i= first_tab + mat_info->tables; i <= idx; i++)
{ {
best_access_path(join, join->positions[i].table, rem_tables, i, best_access_path(join, join->positions[i].table, rem_tables, i,
@ -3590,6 +3597,12 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
table_map handled_tabs= 0; table_map handled_tabs= 0;
join->sjm_lookup_tables= 0; join->sjm_lookup_tables= 0;
join->sjm_scan_tables= 0; join->sjm_scan_tables= 0;
THD *thd= join->thd;
if (!join->select_lex->sj_nests.elements)
return;
Json_writer_object trace_wrapper(thd);
Json_writer_array trace_semijoin_strategies(thd,
"fix_semijoin_strategies_for_picked_join_order");
for (tablenr= table_count - 1 ; tablenr != join->const_tables - 1; tablenr--) for (tablenr= table_count - 1 ; tablenr != join->const_tables - 1; tablenr--)
{ {
POSITION *pos= join->best_positions + tablenr; POSITION *pos= join->best_positions + tablenr;
@ -3614,9 +3627,19 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
first= tablenr - sjm->tables + 1; first= tablenr - sjm->tables + 1;
join->best_positions[first].n_sj_tables= sjm->tables; join->best_positions[first].n_sj_tables= sjm->tables;
join->best_positions[first].sj_strategy= SJ_OPT_MATERIALIZE; join->best_positions[first].sj_strategy= SJ_OPT_MATERIALIZE;
Json_writer_object semijoin_strategy(thd);
semijoin_strategy.add("semi_join_strategy","sj_materialize");
Json_writer_array semijoin_plan(thd, "join_order");
for (uint i= first; i < first+ sjm->tables; i++) for (uint i= first; i < first+ sjm->tables; i++)
{
if (unlikely(thd->trace_started()))
{
Json_writer_object trace_one_table(thd);
trace_one_table.add_table_name(join->best_positions[i].table);
}
join->sjm_lookup_tables |= join->best_positions[i].table->table->map; join->sjm_lookup_tables |= join->best_positions[i].table->table->map;
} }
}
else if (pos->sj_strategy == SJ_OPT_MATERIALIZE_SCAN) else if (pos->sj_strategy == SJ_OPT_MATERIALIZE_SCAN)
{ {
POSITION *first_inner= join->best_positions + pos->sjmat_picker.sjm_scan_last_inner; POSITION *first_inner= join->best_positions + pos->sjmat_picker.sjm_scan_last_inner;
@ -3653,8 +3676,16 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
POSITION dummy; POSITION dummy;
join->cur_sj_inner_tables= 0; join->cur_sj_inner_tables= 0;
Json_writer_object semijoin_strategy(thd);
semijoin_strategy.add("semi_join_strategy","sj_materialize_scan");
Json_writer_array semijoin_plan(thd, "join_order");
for (i= first + sjm->tables; i <= tablenr; i++) for (i= first + sjm->tables; i <= tablenr; i++)
{ {
if (unlikely(thd->trace_started()))
{
Json_writer_object trace_one_table(thd);
trace_one_table.add_table_name(join->best_positions[i].table);
}
best_access_path(join, join->best_positions[i].table, rem_tables, i, best_access_path(join, join->best_positions[i].table, rem_tables, i,
FALSE, prefix_rec_count, FALSE, prefix_rec_count,
join->best_positions + i, &dummy); join->best_positions + i, &dummy);
@ -3683,8 +3714,16 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
join buffering join buffering
*/ */
join->cur_sj_inner_tables= 0; join->cur_sj_inner_tables= 0;
Json_writer_object semijoin_strategy(thd);
semijoin_strategy.add("semi_join_strategy","firstmatch");
Json_writer_array semijoin_plan(thd, "join_order");
for (idx= first; idx <= tablenr; idx++) for (idx= first; idx <= tablenr; idx++)
{ {
if (unlikely(thd->trace_started()))
{
Json_writer_object trace_one_table(thd);
trace_one_table.add_table_name(join->best_positions[idx].table);
}
if (join->best_positions[idx].use_join_buffer) if (join->best_positions[idx].use_join_buffer)
{ {
best_access_path(join, join->best_positions[idx].table, best_access_path(join, join->best_positions[idx].table,
@ -3713,8 +3752,16 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
join buffering join buffering
*/ */
join->cur_sj_inner_tables= 0; join->cur_sj_inner_tables= 0;
Json_writer_object semijoin_strategy(thd);
semijoin_strategy.add("semi_join_strategy","sj_materialize");
Json_writer_array semijoin_plan(thd, "join_order");
for (idx= first; idx <= tablenr; idx++) for (idx= first; idx <= tablenr; idx++)
{ {
if (unlikely(thd->trace_started()))
{
Json_writer_object trace_one_table(thd);
trace_one_table.add_table_name(join->best_positions[idx].table);
}
if (join->best_positions[idx].use_join_buffer || (idx == first)) if (join->best_positions[idx].use_join_buffer || (idx == first))
{ {
best_access_path(join, join->best_positions[idx].table, best_access_path(join, join->best_positions[idx].table,

View File

@ -525,7 +525,7 @@ eliminate_tables_for_list(JOIN *join,
table_map tables_in_list, table_map tables_in_list,
Item *on_expr, Item *on_expr,
table_map tables_used_elsewhere, table_map tables_used_elsewhere,
Json_writer_array* eliminate_tables); Json_writer_array* trace_eliminate_tables);
static static
bool check_func_dependency(JOIN *join, bool check_func_dependency(JOIN *join,
table_map dep_tables, table_map dep_tables,
@ -545,7 +545,7 @@ Dep_module_expr *merge_eq_mods(Dep_module_expr *start,
Dep_module_expr *new_fields, Dep_module_expr *new_fields,
Dep_module_expr *end, uint and_level); Dep_module_expr *end, uint and_level);
static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl, static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl,
Json_writer_array* eliminate_tables); Json_writer_array* trace_eliminate_tables);
static static
void add_module_expr(Dep_analysis_context *dac, Dep_module_expr **eq_mod, void add_module_expr(Dep_analysis_context *dac, Dep_module_expr **eq_mod,
uint and_level, Dep_value_field *field_val, Item *right, uint and_level, Dep_value_field *field_val, Item *right,
@ -671,12 +671,12 @@ void eliminate_tables(JOIN *join)
} }
table_map all_tables= join->all_tables_map(); table_map all_tables= join->all_tables_map();
Json_writer_array eliminated_tables(thd,"eliminated_tables"); Json_writer_array trace_eliminated_tables(thd,"eliminated_tables");
if (all_tables & ~used_tables) if (all_tables & ~used_tables)
{ {
/* There are some tables that we probably could eliminate. Try it. */ /* There are some tables that we probably could eliminate. Try it. */
eliminate_tables_for_list(join, join->join_list, all_tables, NULL, eliminate_tables_for_list(join, join->join_list, all_tables, NULL,
used_tables, &eliminated_tables); used_tables, &trace_eliminated_tables);
} }
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
@ -720,7 +720,7 @@ static bool
eliminate_tables_for_list(JOIN *join, List<TABLE_LIST> *join_list, eliminate_tables_for_list(JOIN *join, List<TABLE_LIST> *join_list,
table_map list_tables, Item *on_expr, table_map list_tables, Item *on_expr,
table_map tables_used_elsewhere, table_map tables_used_elsewhere,
Json_writer_array *eliminate_tables) Json_writer_array *trace_eliminate_tables)
{ {
TABLE_LIST *tbl; TABLE_LIST *tbl;
List_iterator<TABLE_LIST> it(*join_list); List_iterator<TABLE_LIST> it(*join_list);
@ -742,9 +742,10 @@ eliminate_tables_for_list(JOIN *join, List<TABLE_LIST> *join_list,
&tbl->nested_join->join_list, &tbl->nested_join->join_list,
tbl->nested_join->used_tables, tbl->nested_join->used_tables,
tbl->on_expr, tbl->on_expr,
outside_used_tables, eliminate_tables)) outside_used_tables,
trace_eliminate_tables))
{ {
mark_as_eliminated(join, tbl, eliminate_tables); mark_as_eliminated(join, tbl, trace_eliminate_tables);
} }
else else
all_eliminated= FALSE; all_eliminated= FALSE;
@ -756,7 +757,7 @@ eliminate_tables_for_list(JOIN *join, List<TABLE_LIST> *join_list,
check_func_dependency(join, tbl->table->map, NULL, tbl, check_func_dependency(join, tbl->table->map, NULL, tbl,
tbl->on_expr)) tbl->on_expr))
{ {
mark_as_eliminated(join, tbl, eliminate_tables); mark_as_eliminated(join, tbl, trace_eliminate_tables);
} }
else else
all_eliminated= FALSE; all_eliminated= FALSE;
@ -1797,7 +1798,7 @@ Dep_module* Dep_value_field::get_next_unbound_module(Dep_analysis_context *dac,
*/ */
static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl, static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl,
Json_writer_array* eliminate_tables) Json_writer_array* trace_eliminate_tables)
{ {
TABLE *table; TABLE *table;
/* /*
@ -1810,7 +1811,7 @@ static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl,
TABLE_LIST *child; TABLE_LIST *child;
List_iterator<TABLE_LIST> it(tbl->nested_join->join_list); List_iterator<TABLE_LIST> it(tbl->nested_join->join_list);
while ((child= it++)) while ((child= it++))
mark_as_eliminated(join, child, eliminate_tables); mark_as_eliminated(join, child, trace_eliminate_tables);
} }
else if ((table= tbl->table)) else if ((table= tbl->table))
{ {
@ -1821,7 +1822,7 @@ static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl,
tab->type= JT_CONST; tab->type= JT_CONST;
tab->table->const_table= 1; tab->table->const_table= 1;
join->eliminated_tables |= table->map; join->eliminated_tables |= table->map;
eliminate_tables->add(table->alias.c_ptr_safe()); trace_eliminate_tables->add(table->alias.c_ptr_safe());
join->const_table_map|= table->map; join->const_table_map|= table->map;
set_position(join, join->const_tables++, tab, (KEYUSE*)0); set_position(join, join->const_tables++, tab, (KEYUSE*)0);
} }

View File

@ -66,7 +66,8 @@ bool sets_var_optimizer_trace(enum enum_sql_command sql_command,
} }
ST_FIELD_INFO optimizer_trace_info[] = { ST_FIELD_INFO optimizer_trace_info[]=
{
/* name, length, type, value, maybe_null, old_name, open_method */ /* name, length, type, value, maybe_null, old_name, open_method */
{"QUERY", 65535, MYSQL_TYPE_STRING, 0, false, NULL, SKIP_OPEN_TABLE}, {"QUERY", 65535, MYSQL_TYPE_STRING, 0, false, NULL, SKIP_OPEN_TABLE},
{"TRACE", 65535, MYSQL_TYPE_STRING, 0, false, NULL, SKIP_OPEN_TABLE}, {"TRACE", 65535, MYSQL_TYPE_STRING, 0, false, NULL, SKIP_OPEN_TABLE},
@ -74,7 +75,8 @@ ST_FIELD_INFO optimizer_trace_info[] = {
SKIP_OPEN_TABLE}, SKIP_OPEN_TABLE},
{"INSUFFICIENT_PRIVILEGES", 1, MYSQL_TYPE_TINY, 0, false, NULL, {"INSUFFICIENT_PRIVILEGES", 1, MYSQL_TYPE_TINY, 0, false, NULL,
SKIP_OPEN_TABLE}, SKIP_OPEN_TABLE},
{NULL, 0, MYSQL_TYPE_STRING, 0, true, NULL, 0}}; {NULL, 0, MYSQL_TYPE_STRING, 0, true, NULL, 0}
};
/* /*
TODO: one-line needs to be implemented seperately TODO: one-line needs to be implemented seperately
@ -105,15 +107,15 @@ void opt_trace_print_expanded_query(THD *thd, SELECT_LEX *select_lex,
{ {
if (!thd->trace_started()) if (!thd->trace_started())
return; return;
char buff[1024]; StringBuffer<1024> str(system_charset_info);
String str(buff, sizeof(buff), system_charset_info); ulonglong save_option_bits= thd->variables.option_bits;
str.length(0); thd->variables.option_bits &= ~OPTION_QUOTE_SHOW_CREATE;
select_lex->print(thd, &str, select_lex->print(thd, &str,
enum_query_type(QT_TO_SYSTEM_CHARSET | enum_query_type(QT_TO_SYSTEM_CHARSET |
QT_SHOW_SELECT_NUMBER | QT_SHOW_SELECT_NUMBER |
QT_ITEM_IDENT_SKIP_DB_NAMES | QT_ITEM_IDENT_SKIP_DB_NAMES |
QT_VIEW_INTERNAL QT_VIEW_INTERNAL));
)); thd->variables.option_bits= save_option_bits;
/* /*
The output is not very pretty lots of back-ticks, the output The output is not very pretty lots of back-ticks, the output
is as the one in explain extended , lets try to improved it here. is as the one in explain extended , lets try to improved it here.
@ -187,7 +189,6 @@ void opt_trace_disable_if_no_security_context_access(THD *thd)
thd->main_security_ctx.priv_host, thd->main_security_ctx.priv_host,
thd->security_context()->priv_host))) thd->security_context()->priv_host)))
trace->missing_privilege(); trace->missing_privilege();
return;
} }
void opt_trace_disable_if_no_stored_proc_func_access(THD *thd, sp_head *sp) void opt_trace_disable_if_no_stored_proc_func_access(THD *thd, sp_head *sp)
@ -207,7 +208,6 @@ void opt_trace_disable_if_no_stored_proc_func_access(THD *thd, sp_head *sp)
thd->set_security_context(backup_thd_sctx); thd->set_security_context(backup_thd_sctx);
if (rc) if (rc)
trace->missing_privilege(); trace->missing_privilege();
return;
} }
/** /**
@ -347,9 +347,6 @@ class Opt_trace_stmt {
~Opt_trace_stmt() ~Opt_trace_stmt()
{ {
delete current_json; delete current_json;
missing_priv= false;
ctx= NULL;
I_S_disabled= 0;
} }
void set_query(const char *query_ptr, size_t length, const CHARSET_INFO *charset); void set_query(const char *query_ptr, size_t length, const CHARSET_INFO *charset);
void open_struct(const char *key, char opening_bracket); void open_struct(const char *key, char opening_bracket);
@ -372,6 +369,12 @@ private:
String query; // store the query sent by the user String query; // store the query sent by the user
Json_writer *current_json; // stores the trace Json_writer *current_json; // stores the trace
bool missing_priv; ///< whether user lacks privilege to see this trace bool missing_priv; ///< whether user lacks privilege to see this trace
/*
0 <=> this trace should be in information_schema.
!=0 tracing is disabled, this currently happens when we want to trace a
sub-statement. For now traces are only collect for the top statement
not for the sub-statments.
*/
uint I_S_disabled; uint I_S_disabled;
}; };
@ -440,28 +443,11 @@ bool Opt_trace_context::is_enabled()
Opt_trace_context::Opt_trace_context() Opt_trace_context::Opt_trace_context()
{ {
current_trace= NULL; current_trace= NULL;
inited= FALSE;
traces= NULL;
max_mem_size= 0; max_mem_size= 0;
} }
Opt_trace_context::~Opt_trace_context() Opt_trace_context::~Opt_trace_context()
{ {
inited= FALSE; delete_traces();
/*
would be nice to move this to a function
*/
if (traces)
{
while (traces->elements())
{
Opt_trace_stmt *prev= traces->at(0);
delete prev;
traces->del(0);
}
delete traces;
traces= NULL;
}
max_mem_size= 0;
} }
void Opt_trace_context::set_query(const char *query, size_t length, const CHARSET_INFO *charset) void Opt_trace_context::set_query(const char *query, size_t length, const CHARSET_INFO *charset)
@ -487,26 +473,21 @@ void Opt_trace_context::start(THD *thd, TABLE_LIST *tbl,
DBUG_ASSERT(!current_trace); DBUG_ASSERT(!current_trace);
current_trace= new Opt_trace_stmt(this); current_trace= new Opt_trace_stmt(this);
max_mem_size= max_mem_size_arg; max_mem_size= max_mem_size_arg;
if (!inited)
{
traces= new Dynamic_array<Opt_trace_stmt*>();
inited= TRUE;
}
set_allowed_mem_size(remaining_mem_size()); set_allowed_mem_size(remaining_mem_size());
} }
void Opt_trace_context::end() void Opt_trace_context::end()
{ {
if (current_trace) if (current_trace)
traces->push(current_trace); traces.push(current_trace);
if (!traces->elements()) if (!traces.elements())
return; return;
if (traces->elements() > 1) if (traces.elements() > 1)
{ {
Opt_trace_stmt *prev= traces->at(0); Opt_trace_stmt *prev= traces.at(0);
delete prev; delete prev;
traces->del(0); traces.del(0);
} }
current_trace= NULL; current_trace= NULL;
} }
@ -659,9 +640,7 @@ void Json_writer::add_str(Item *item)
if (item) if (item)
{ {
THD *thd= current_thd; THD *thd= current_thd;
char buff[256]; StringBuffer<256> str(system_charset_info);
String str(buff, sizeof(buff), system_charset_info);
str.length(0);
ulonglong save_option_bits= thd->variables.option_bits; ulonglong save_option_bits= thd->variables.option_bits;
thd->variables.option_bits &= ~OPTION_QUOTE_SHOW_CREATE; thd->variables.option_bits &= ~OPTION_QUOTE_SHOW_CREATE;
@ -675,19 +654,16 @@ void Json_writer::add_str(Item *item)
add_null(); add_null();
} }
void Opt_trace_context::flush_optimizer_trace() void Opt_trace_context::delete_traces()
{ {
inited= false; if (traces.elements())
if (traces)
{ {
while (traces->elements()) while (traces.elements())
{ {
Opt_trace_stmt *prev= traces->at(0); Opt_trace_stmt *prev= traces.at(0);
delete prev; delete prev;
traces->del(0); traces.del(0);
} }
delete traces;
traces= NULL;
} }
} }
@ -703,7 +679,7 @@ int fill_optimizer_trace_info(THD *thd, TABLE_LIST *tables, Item *)
*/ */
Opt_trace_context* ctx= &thd->opt_trace; Opt_trace_context* ctx= &thd->opt_trace;
if (thd->opt_trace.empty()) if (!thd->opt_trace.empty())
{ {
Opt_trace_stmt *stmt= ctx->get_top_trace(); Opt_trace_stmt *stmt= ctx->get_top_trace();
stmt->fill_info(&info); stmt->fill_info(&info);

View File

@ -193,9 +193,16 @@ void opt_trace_disable_if_no_stored_proc_func_access(THD *thd, sp_head *sp);
*/ */
int fill_optimizer_trace_info(THD *thd, TABLE_LIST *tables, Item *); int fill_optimizer_trace_info(THD *thd, TABLE_LIST *tables, Item *);
#define OPT_TRACE_TRANSFORM(writer, object_level0, object_level1, \ #define OPT_TRACE_TRANSFORM(thd, object_level0, object_level1, \
select_number, from, to) \ select_number, from, to) \
Json_writer_object object_level0(writer); \ Json_writer_object object_level0(thd); \
Json_writer_object object_level1(writer, "transformation"); \ Json_writer_object object_level1(thd, "transformation"); \
object_level1.add_select_number(select_number).add("from", from).add("to", to); object_level1.add_select_number(select_number).add("from", from).add("to", to);
#define OPT_TRACE_VIEWS_TRANSFORM(thd, object_level0, object_level1, \
derived, name, select_number, algorithm) \
Json_writer_object trace_wrapper(thd); \
Json_writer_object trace_derived(thd, derived); \
trace_derived.add("table", name).add_select_number(select_number) \
.add("algorithm", algorithm);
#endif #endif

View File

@ -19,14 +19,14 @@ public:
ulong max_mem_size_arg); ulong max_mem_size_arg);
void end(); void end();
void set_query(const char *query, size_t length, const CHARSET_INFO *charset); void set_query(const char *query, size_t length, const CHARSET_INFO *charset);
void flush_optimizer_trace(); void delete_traces();
void set_allowed_mem_size(size_t mem_size); void set_allowed_mem_size(size_t mem_size);
size_t remaining_mem_size(); size_t remaining_mem_size();
private: private:
Opt_trace_stmt* top_trace() Opt_trace_stmt* top_trace()
{ {
return *(traces->front()); return *(traces.front());
} }
public: public:
@ -39,7 +39,7 @@ public:
Opt_trace_stmt* get_top_trace() Opt_trace_stmt* get_top_trace()
{ {
if (!traces || !traces->elements()) if (!traces.elements())
return NULL; return NULL;
return top_trace(); return top_trace();
} }
@ -52,7 +52,7 @@ public:
bool empty() bool empty()
{ {
return traces && (static_cast<uint>(traces->elements()) != 0); return static_cast<uint>(traces.elements()) == 0;
} }
bool is_started() bool is_started()
@ -79,13 +79,8 @@ private:
/* /*
List of traces (currently it stores only 1 trace) List of traces (currently it stores only 1 trace)
*/ */
Dynamic_array<Opt_trace_stmt*> *traces; Dynamic_array<Opt_trace_stmt*> traces;
Opt_trace_stmt *current_trace; Opt_trace_stmt *current_trace;
/*
TRUE: if we allocate memory for list of traces
FALSE: otherwise
*/
bool inited;
size_t max_mem_size; size_t max_mem_size;
}; };

View File

@ -1411,7 +1411,7 @@ void THD::change_user(void)
sp_cache_clear(&sp_func_cache); sp_cache_clear(&sp_func_cache);
sp_cache_clear(&sp_package_spec_cache); sp_cache_clear(&sp_package_spec_cache);
sp_cache_clear(&sp_package_body_cache); sp_cache_clear(&sp_package_body_cache);
opt_trace.flush_optimizer_trace(); opt_trace.delete_traces();
} }
/** /**

View File

@ -34,6 +34,7 @@
#include "sql_class.h" #include "sql_class.h"
#include "sql_cte.h" #include "sql_cte.h"
#include "my_json_writer.h" #include "my_json_writer.h"
#include "opt_trace.h"
typedef bool (*dt_processor)(THD *thd, LEX *lex, TABLE_LIST *derived); typedef bool (*dt_processor)(THD *thd, LEX *lex, TABLE_LIST *derived);
@ -384,6 +385,15 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
{ {
/* There is random function => fall back to materialization. */ /* There is random function => fall back to materialization. */
cause= "Random function in the select"; cause= "Random function in the select";
if (unlikely(thd->trace_started()))
{
OPT_TRACE_VIEWS_TRANSFORM(thd, trace_wrapper, trace_derived,
derived->is_derived() ? "derived" : "view",
derived->alias.str ? derived->alias.str : "<NULL>",
derived->get_unit()->first_select()->select_number,
"materialized");
trace_derived.add("cause", cause);
}
derived->change_refs_to_fields(); derived->change_refs_to_fields();
derived->set_materialized_derived(); derived->set_materialized_derived();
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
@ -497,19 +507,12 @@ unconditional_materialization:
if (unlikely(thd->trace_started())) if (unlikely(thd->trace_started()))
{ {
/* OPT_TRACE_VIEWS_TRANSFORM(thd,trace_wrapper, trace_derived,
Add to the optimizer trace the change in choice for merged derived->is_derived() ? "derived" : "view",
derived tables/views to materialised ones. derived->alias.str ? derived->alias.str : "<NULL>",
*/ derived->get_unit()->first_select()->select_number,
Json_writer_object trace_wrapper(thd); "materialized");
Json_writer_object trace_derived(thd, derived->is_derived() ? trace_derived.add("cause", cause);
"derived" : "view");
trace_derived.add("table", derived->alias.str ? derived->alias.str : "<NULL>")
.add_select_number(derived->get_unit()->
first_select()->select_number)
.add("initial_choice", "merged")
.add("final_choice", "materialized")
.add("cause", cause);
} }
derived->change_refs_to_fields(); derived->change_refs_to_fields();
@ -778,15 +781,11 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
Add to optimizer trace whether a derived table/view Add to optimizer trace whether a derived table/view
is merged into the parent select or not. is merged into the parent select or not.
*/ */
Json_writer_object trace_wrapper(thd); OPT_TRACE_VIEWS_TRANSFORM(thd, trace_wrapper, trace_derived,
Json_writer_object trace_derived(thd, derived->is_derived() ? derived->is_derived() ? "derived" : "view",
"derived" : "view"); derived->alias.str ? derived->alias.str : "<NULL>",
trace_derived.add("table", derived->alias.str ? derived->alias.str : "<NULL>") derived->get_unit()->first_select()->select_number,
.add_select_number(derived->get_unit()->first_select()->select_number); derived->is_merged_derived() ? "merged" : "materialized");
if (derived->is_materialized_derived())
trace_derived.add("materialized", true);
if (derived->is_merged_derived())
trace_derived.add("merged", true);
} }
/* /*
Above cascade call of prepare is important for PS protocol, but after it Above cascade call of prepare is important for PS protocol, but after it

View File

@ -121,6 +121,7 @@ static bool best_extension_by_limited_search(JOIN *join,
double read_time, uint depth, double read_time, uint depth,
uint prune_level, uint prune_level,
uint use_cond_selectivity); uint use_cond_selectivity);
void trace_plan_prefix(JOIN *join, uint idx, table_map remaining_tables);
static uint determine_search_depth(JOIN* join); static uint determine_search_depth(JOIN* join);
C_MODE_START C_MODE_START
static int join_tab_cmp(const void *dummy, const void* ptr1, const void* ptr2); static int join_tab_cmp(const void *dummy, const void* ptr1, const void* ptr2);
@ -302,8 +303,6 @@ void set_postjoin_aggr_write_func(JOIN_TAB *tab);
static Item **get_sargable_cond(JOIN *join, TABLE *table); static Item **get_sargable_cond(JOIN *join, TABLE *table);
static void trace_plan_prefix(JOIN *join, uint idx, table_map remaining_tables);
#ifndef DBUG_OFF #ifndef DBUG_OFF
/* /*
@ -377,14 +376,10 @@ static void trace_table_dependencies(THD *thd,
} }
} }
Json_writer_array depends_on(thd, "depends_on_map_bits"); Json_writer_array depends_on(thd, "depends_on_map_bits");
static_assert(sizeof(table_ref->get_map()) <= 64, Table_map_iterator it(join_tabs[i].dependent);
"RAND_TABLE_BIT may be in join_tabs[i].dependent, so we test " uint dep_bit;
"all 64 bits."); while ((dep_bit= it++) != Table_map_iterator::BITMAP_END)
for (uint j = 0; j < 64; j++) depends_on.add(static_cast<longlong>(dep_bit));
{
if (join_tabs[i].dependent & (1ULL << j))
depends_on.add(static_cast<longlong>(j));
}
} }
} }
@ -9045,7 +9040,7 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
} }
static void trace_plan_prefix(JOIN *join, uint idx, table_map remaining_tables) void trace_plan_prefix(JOIN *join, uint idx, table_map remaining_tables)
{ {
THD *const thd= join->thd; THD *const thd= join->thd;
Json_writer_array plan_prefix(thd, "plan_prefix"); Json_writer_array plan_prefix(thd, "plan_prefix");
@ -9261,9 +9256,6 @@ best_extension_by_limited_search(JOIN *join,
current_record_count / (double) TIME_FOR_COMPARE - current_record_count / (double) TIME_FOR_COMPARE -
filter_cmp_gain; filter_cmp_gain;
/*
TODO add filtering estimates here
*/
advance_sj_state(join, remaining_tables, idx, &current_record_count, advance_sj_state(join, remaining_tables, idx, &current_record_count,
&current_read_time, &loose_scan_pos); &current_read_time, &loose_scan_pos);
@ -11070,12 +11062,6 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
tab->table->intersect_keys.is_set(tab->ref.key)))) tab->table->intersect_keys.is_set(tab->ref.key))))
{ {
/* Range uses longer key; Use this instead of ref on key */ /* Range uses longer key; Use this instead of ref on key */
/*
We can trace here, changing ref access to range access here
have a range that uses longer key.
Lets take @spetrunia's opinion
*/
Json_writer_object ref_to_range(thd); Json_writer_object ref_to_range(thd);
ref_to_range.add("ref_to_range", true); ref_to_range.add("ref_to_range", true);
ref_to_range.add("cause", "range uses longer key"); ref_to_range.add("cause", "range uses longer key");
@ -16413,6 +16399,8 @@ void optimize_wo_join_buffering(JOIN *join, uint first_tab, uint last_tab,
double cost, rec_count; double cost, rec_count;
table_map reopt_remaining_tables= last_remaining_tables; table_map reopt_remaining_tables= last_remaining_tables;
uint i; uint i;
THD *thd= join->thd;
Json_writer_temp_disable trace_wo_join_buffering(thd);
if (first_tab > join->const_tables) if (first_tab > join->const_tables)
{ {

View File

@ -665,11 +665,11 @@ void print_keyuse_array_for_trace(THD *thd, DYNAMIC_ARRAY *keyuse_array)
KEYUSE *keyuse= (KEYUSE*)dynamic_array_ptr(keyuse_array, i); KEYUSE *keyuse= (KEYUSE*)dynamic_array_ptr(keyuse_array, i);
Json_writer_object keyuse_elem(thd); Json_writer_object keyuse_elem(thd);
keyuse_elem.add_table_name(keyuse->table->reginfo.join_tab); keyuse_elem.add_table_name(keyuse->table->reginfo.join_tab);
keyuse_elem.add("field", (keyuse->keypart == FT_KEYPART) ? "<fulltext>" keyuse_elem.add("field", (keyuse->keypart == FT_KEYPART) ? "<fulltext>":
: (keyuse->is_for_hash_join() (keyuse->is_for_hash_join() ?
? keyuse->table->field[keyuse->keypart] keyuse->table->field[keyuse->keypart]
->field_name.str ->field_name.str :
: keyuse->table->key_info[keyuse->key] keyuse->table->key_info[keyuse->key]
.key_part[keyuse->keypart] .key_part[keyuse->keypart]
.field->field_name.str)); .field->field_name.str));
keyuse_elem.add("equals",keyuse->val); keyuse_elem.add("equals",keyuse->val);