mirror of
https://github.com/MariaDB/server.git
synced 2026-01-06 05:22:24 +03:00
MDEV-20444: More information regarding access of a table to be printed inside the optimizer_trace
Added:
1) estimated_join_cardinality
2) best_chosen_access_method for a table
3) best_join_order
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -207,18 +207,29 @@ explain select * from t1 where a=1 or b=1 {
|
||||
"best_access_path": {
|
||||
"considered_access_paths": [
|
||||
{
|
||||
"access_type": "range",
|
||||
"access_type": "index_merge",
|
||||
"resulting_rows": 2,
|
||||
"cost": 4.1484,
|
||||
"chosen": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"chosen_access_method": {
|
||||
"type": "index_merge",
|
||||
"records": 2,
|
||||
"cost": 4.1484,
|
||||
"uses_join_buffering": false,
|
||||
"filter_used": false
|
||||
}
|
||||
},
|
||||
"rows_for_plan": 2,
|
||||
"cost_for_plan": 4.5484
|
||||
"cost_for_plan": 4.5484,
|
||||
"estimated_join_cardinality": 2
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"best_join_order": ["t1"]
|
||||
},
|
||||
{
|
||||
"attaching_conditions_to_tables": {
|
||||
"original_condition": "t1.a = 1 or t1.b = 1",
|
||||
|
||||
@@ -208,13 +208,24 @@ explain select * from t1 where pk1 != 0 and key1 = 1 {
|
||||
"chosen": false,
|
||||
"cause": "cost"
|
||||
}
|
||||
]
|
||||
],
|
||||
"chosen_access_method": {
|
||||
"type": "ref",
|
||||
"records": 1,
|
||||
"cost": 2,
|
||||
"uses_join_buffering": false,
|
||||
"filter_used": false
|
||||
}
|
||||
},
|
||||
"rows_for_plan": 1,
|
||||
"cost_for_plan": 2.2
|
||||
"cost_for_plan": 2.2,
|
||||
"estimated_join_cardinality": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"best_join_order": ["t1"]
|
||||
},
|
||||
{
|
||||
"attaching_conditions_to_tables": {
|
||||
"original_condition": "t1.key1 = 1 and t1.pk1 <> 0",
|
||||
|
||||
@@ -98,13 +98,24 @@ select * from db1.t1 {
|
||||
"cost": 2.0051,
|
||||
"chosen": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"chosen_access_method": {
|
||||
"type": "scan",
|
||||
"records": 3,
|
||||
"cost": 2.0051,
|
||||
"uses_join_buffering": false,
|
||||
"filter_used": false
|
||||
}
|
||||
},
|
||||
"rows_for_plan": 3,
|
||||
"cost_for_plan": 2.6051
|
||||
"cost_for_plan": 2.6051,
|
||||
"estimated_join_cardinality": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"best_join_order": ["t1"]
|
||||
},
|
||||
{
|
||||
"attaching_conditions_to_tables": {
|
||||
"original_condition": null,
|
||||
@@ -211,13 +222,24 @@ select * from db1.v1 {
|
||||
"cost": 2.0051,
|
||||
"chosen": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"chosen_access_method": {
|
||||
"type": "scan",
|
||||
"records": 3,
|
||||
"cost": 2.0051,
|
||||
"uses_join_buffering": false,
|
||||
"filter_used": false
|
||||
}
|
||||
},
|
||||
"rows_for_plan": 3,
|
||||
"cost_for_plan": 2.6051
|
||||
"cost_for_plan": 2.6051,
|
||||
"estimated_join_cardinality": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"best_join_order": ["t1"]
|
||||
},
|
||||
{
|
||||
"attaching_conditions_to_tables": {
|
||||
"original_condition": null,
|
||||
|
||||
@@ -630,6 +630,45 @@ void add_table_scan_values_to_trace(THD *thd, JOIN_TAB *tab)
|
||||
table_rec.add("rows", tab->found_records)
|
||||
.add("cost", tab->read_time);
|
||||
}
|
||||
|
||||
/*
|
||||
Print the join order of all the tables for top level select.
|
||||
|
||||
For example:
|
||||
|
||||
select * from ot1
|
||||
where ot1.a IN (select it1.a from it1, it2 where it1.b=it2.a);
|
||||
|
||||
So this function would print
|
||||
ot1, <subquery2> ----> For select #1
|
||||
*/
|
||||
|
||||
void print_final_join_order(JOIN *join)
|
||||
{
|
||||
Json_writer_object join_order(join->thd);
|
||||
Json_writer_array best_order(join->thd, "best_join_order");
|
||||
JOIN_TAB *j;
|
||||
uint i;
|
||||
for (j= join->join_tab,i=0 ; i < join->top_join_tab_count;
|
||||
i++, j++)
|
||||
best_order.add_table_name(j);
|
||||
}
|
||||
|
||||
|
||||
void print_best_access_for_table(THD *thd, POSITION *pos,
|
||||
enum join_type type)
|
||||
{
|
||||
Json_writer_object trace_best_access(thd, "chosen_access_method");
|
||||
trace_best_access.add("type", type == JT_ALL ? "scan" :
|
||||
join_type_str[type]);
|
||||
trace_best_access.add("records", pos->records_read);
|
||||
trace_best_access.add("cost", pos->read_time);
|
||||
trace_best_access.add("uses_join_buffering", pos->use_join_buffer);
|
||||
trace_best_access.add("filter_used",
|
||||
pos->range_rowid_filter_info != NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Introduce enum_query_type flags parameter, maybe also allow
|
||||
EXPLAIN also use this function.
|
||||
|
||||
@@ -105,6 +105,9 @@ void opt_trace_print_expanded_query(THD *thd, SELECT_LEX *select_lex,
|
||||
Json_writer_object *trace_object);
|
||||
|
||||
void add_table_scan_values_to_trace(THD *thd, JOIN_TAB *tab);
|
||||
void print_final_join_order(JOIN *join);
|
||||
void print_best_access_for_table(THD *thd, POSITION *pos,
|
||||
enum join_type type);
|
||||
|
||||
/*
|
||||
Security related (need to add a proper comment here)
|
||||
|
||||
@@ -7203,6 +7203,7 @@ best_access_path(JOIN *join,
|
||||
SplM_plan_info *spl_plan= 0;
|
||||
Range_rowid_filter_cost_info *filter= 0;
|
||||
const char* cause= NULL;
|
||||
enum join_type best_type= JT_UNKNOWN, type= JT_UNKNOWN;
|
||||
|
||||
disable_jbuf= disable_jbuf || idx == join->const_tables;
|
||||
|
||||
@@ -7342,7 +7343,8 @@ best_access_path(JOIN *join,
|
||||
*/
|
||||
tmp= prev_record_reads(join->positions, idx, found_ref);
|
||||
records= 1.0;
|
||||
trace_access_idx.add("access_type", "fulltext")
|
||||
type= JT_FT;
|
||||
trace_access_idx.add("access_type", join_type_str[type])
|
||||
.add("index", keyinfo->name);
|
||||
}
|
||||
else
|
||||
@@ -7365,14 +7367,16 @@ best_access_path(JOIN *join,
|
||||
(!(key_flags & HA_NULL_PART_KEY) || // (2)
|
||||
all_key_parts == notnull_part)) // (3)
|
||||
{
|
||||
trace_access_idx.add("access_type", "eq_ref")
|
||||
type= JT_EQ_REF;
|
||||
trace_access_idx.add("access_type", join_type_str[type])
|
||||
.add("index", keyinfo->name);
|
||||
tmp = prev_record_reads(join->positions, idx, found_ref);
|
||||
records=1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
trace_access_idx.add("access_type", "ref")
|
||||
type= JT_REF;
|
||||
trace_access_idx.add("access_type", join_type_str[type])
|
||||
.add("index", keyinfo->name);
|
||||
if (!found_ref)
|
||||
{ /* We found a const key */
|
||||
@@ -7467,8 +7471,8 @@ best_access_path(JOIN *join,
|
||||
}
|
||||
else
|
||||
{
|
||||
trace_access_idx.add("access_type",
|
||||
ref_or_null_part ? "ref_or_null" : "ref")
|
||||
type = ref_or_null_part ? JT_REF_OR_NULL : JT_REF;
|
||||
trace_access_idx.add("access_type", join_type_str[type])
|
||||
.add("index", keyinfo->name);
|
||||
/*
|
||||
Use as much key-parts as possible and a uniq key is better
|
||||
@@ -7683,6 +7687,7 @@ best_access_path(JOIN *join,
|
||||
best_max_key_part= max_key_part;
|
||||
best_ref_depends_map= found_ref;
|
||||
best_filter= filter;
|
||||
best_type= type;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -7736,6 +7741,7 @@ best_access_path(JOIN *join,
|
||||
best_ref_depends_map= 0;
|
||||
best_uses_jbuf= TRUE;
|
||||
best_filter= 0;
|
||||
best_type= JT_HASH;
|
||||
trace_access_hash.add("type", "hash");
|
||||
trace_access_hash.add("index", "hj-key");
|
||||
trace_access_hash.add("cost", rnd_records);
|
||||
@@ -7799,10 +7805,6 @@ best_access_path(JOIN *join,
|
||||
filter= 0;
|
||||
if (s->quick)
|
||||
{
|
||||
trace_access_scan.add("access_type", "range");
|
||||
/*
|
||||
should have some info about all the different QUICK_SELECT
|
||||
*/
|
||||
/*
|
||||
For each record we:
|
||||
- read record range through 'quick'
|
||||
@@ -7828,23 +7830,29 @@ best_access_path(JOIN *join,
|
||||
{
|
||||
tmp-= filter->get_adjusted_gain(rows);
|
||||
DBUG_ASSERT(tmp >= 0);
|
||||
}
|
||||
}
|
||||
type= JT_RANGE;
|
||||
}
|
||||
else
|
||||
{
|
||||
type= JT_INDEX_MERGE;
|
||||
best_filter= 0;
|
||||
}
|
||||
|
||||
loose_scan_opt.check_range_access(join, idx, s->quick);
|
||||
}
|
||||
else
|
||||
{
|
||||
trace_access_scan.add("access_type", "scan");
|
||||
/* Estimate cost of reading table. */
|
||||
if (s->table->force_index && !best_key) // index scan
|
||||
{
|
||||
type= JT_NEXT;
|
||||
tmp= s->table->file->read_time(s->ref.key, 1, s->records);
|
||||
}
|
||||
else // table scan
|
||||
{
|
||||
tmp= s->scan_time();
|
||||
type= JT_ALL;
|
||||
}
|
||||
|
||||
if ((s->table->map & join->outer_join) || disable_jbuf) // Can't use join cache
|
||||
{
|
||||
@@ -7874,6 +7882,9 @@ best_access_path(JOIN *join,
|
||||
}
|
||||
}
|
||||
|
||||
trace_access_scan.add("access_type", type == JT_ALL ?
|
||||
"scan" :
|
||||
join_type_str[type]);
|
||||
/* Splitting technique cannot be used with join cache */
|
||||
if (s->table->is_splittable())
|
||||
tmp+= s->table->get_materialization_cost();
|
||||
@@ -7913,6 +7924,7 @@ best_access_path(JOIN *join,
|
||||
best_uses_jbuf= MY_TEST(!disable_jbuf && !((s->table->map &
|
||||
join->outer_join)));
|
||||
spl_plan= 0;
|
||||
best_type= type;
|
||||
}
|
||||
trace_access_scan.add("chosen", best_key == NULL);
|
||||
}
|
||||
@@ -7944,6 +7956,11 @@ best_access_path(JOIN *join,
|
||||
trace_access_scan.add("use_tmp_table", true);
|
||||
join->sort_by_table= (TABLE*) 1; // Must use temporary table
|
||||
}
|
||||
trace_access_scan.end();
|
||||
trace_paths.end();
|
||||
|
||||
if (unlikely(thd->trace_started()))
|
||||
print_best_access_for_table(thd, pos, best_type);
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@@ -9484,6 +9501,8 @@ best_extension_by_limited_search(JOIN *join,
|
||||
Hence it may be wrong.
|
||||
*/
|
||||
current_read_time= COST_ADD(current_read_time, current_record_count);
|
||||
trace_one_table.add("estimated_join_cardinality",
|
||||
partial_join_cardinality);
|
||||
if (current_read_time < join->best_read)
|
||||
{
|
||||
memcpy((uchar*) join->best_positions, (uchar*) join->positions,
|
||||
@@ -10305,6 +10324,9 @@ bool JOIN::get_best_combination()
|
||||
top_join_tab_count= (uint)(join_tab_ranges.head()->end -
|
||||
join_tab_ranges.head()->start);
|
||||
|
||||
if (unlikely(thd->trace_started()))
|
||||
print_final_join_order(this);
|
||||
|
||||
update_depend_map(this);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user