1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

MDEV-6111 Optimizer Trace

This task involves the implementation for the optimizer trace.

This feature produces a trace for any SELECT/UPDATE/DELETE/,
which contains information about decisions taken by the optimizer during
the optimization phase (choice of table access method, various costs,
transformations, etc). This feature would help to tell why some decisions were
taken by the optimizer and why some were rejected.

Trace is session-local, controlled by the @@optimizer_trace variable.
To enable optimizer trace we need to write:
   set @@optimizer_trace variable= 'enabled=on';

To display the trace one can run:
   SELECT trace FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE;

This task also involves:
    MDEV-18489: Limit the memory used by the optimizer trace
    introduces a switch optimizer_trace_max_mem_size which limits
    the memory used by the optimizer trace. This was implemented by
    Sergei Petrunia.
This commit is contained in:
Varun Gupta
2019-02-13 11:22:16 +05:30
parent 6b979416e0
commit be8709eb7b
47 changed files with 8227 additions and 622 deletions

View File

@ -32,6 +32,7 @@
#include "sql_acl.h" // SELECT_ACL
#include "sql_class.h"
#include "sql_cte.h"
#include "my_json_writer.h"
typedef bool (*dt_processor)(THD *thd, LEX *lex, TABLE_LIST *derived);
@ -198,6 +199,7 @@ mysql_handle_single_derived(LEX *lex, TABLE_LIST *derived, uint phases)
if ((res= (*processors[phase])(lex->thd, lex, derived)))
break;
}
lex->thd->derived_tables_processing= FALSE;
DBUG_RETURN(res);
}
@ -368,6 +370,7 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
DBUG_PRINT("enter", ("Alias: '%s' Unit: %p",
(derived->alias.str ? derived->alias.str : "<NULL>"),
derived->get_unit()));
const char *cause= NULL;
if (derived->merged)
{
@ -379,6 +382,7 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
if (dt_select->uncacheable & UNCACHEABLE_RAND)
{
/* There is random function => fall back to materialization. */
cause= "Random function in the select";
derived->change_refs_to_fields();
derived->set_materialized_derived();
DBUG_RETURN(FALSE);
@ -401,15 +405,11 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
and small subqueries, and the bigger one can't be merged it wouldn't
block the smaller one.
*/
if (parent_lex->get_free_table_map(&map, &tablenr))
{
/* There is no enough table bits, fall back to materialization. */
goto unconditional_materialization;
}
if (dt_select->leaf_tables.elements + tablenr > MAX_TABLES)
if (parent_lex->get_free_table_map(&map, &tablenr) ||
dt_select->leaf_tables.elements + tablenr > MAX_TABLES)
{
/* There is no enough table bits, fall back to materialization. */
cause= "Not enough table bits to merge subquery";
goto unconditional_materialization;
}
@ -486,6 +486,24 @@ exit_merge:
DBUG_RETURN(res);
unconditional_materialization:
if (unlikely(thd->trace_started()))
{
/*
Add to the optimizer trace the change in choice for merged
derived tables/views to materialised ones.
*/
Json_writer_object trace_wrapper(thd);
Json_writer_object trace_derived(thd, derived->is_derived() ?
"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->set_materialized_derived();
if (!derived->table || !derived->table->is_created())
@ -654,7 +672,6 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
DBUG_ENTER("mysql_derived_prepare");
DBUG_PRINT("enter", ("unit: %p table_list: %p alias: '%s'",
unit, derived, derived->alias.str));
if (!unit)
DBUG_RETURN(FALSE);
@ -747,6 +764,22 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
}
}
if (unlikely(thd->trace_started()))
{
/*
Add to optimizer trace whether a derived table/view
is merged into the parent select or not.
*/
Json_writer_object trace_wrapper(thd);
Json_writer_object trace_derived(thd, derived->is_derived() ?
"derived" : "view");
trace_derived.add("table", derived->alias.str ? derived->alias.str : "<NULL>")
.add_select_number(derived->get_unit()->first_select()->select_number);
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
is called we can check if we really need prepare for this derived