summaryrefslogtreecommitdiff
path: root/sql/sql_derived.cc
diff options
context:
space:
mode:
authorVarun Gupta <varun.gupta@mariadb.com>2019-02-13 11:22:16 +0530
committerVarun Gupta <varun.gupta@mariadb.com>2019-02-13 11:52:36 +0530
commitbe8709eb7bdf2a68a1c04fd8ab368113f5f39b63 (patch)
tree35585804a654ec75089a92e90d546f73e7f60b68 /sql/sql_derived.cc
parent6b979416e0e4eac0a036ca5f2b81b748a3d2e680 (diff)
downloadmariadb-git-be8709eb7bdf2a68a1c04fd8ab368113f5f39b63.tar.gz
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.
Diffstat (limited to 'sql/sql_derived.cc')
-rw-r--r--sql/sql_derived.cc49
1 files changed, 41 insertions, 8 deletions
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 878aa715b84..28d28ca2425 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -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