summaryrefslogtreecommitdiffstats
path: root/sql/sql_explain.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_explain.cc')
-rw-r--r--sql/sql_explain.cc168
1 files changed, 161 insertions, 7 deletions
diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc
index 210f229a..b8c9c87c 100644
--- a/sql/sql_explain.cc
+++ b/sql/sql_explain.cc
@@ -36,6 +36,11 @@ const char *unit_operation_text[4]=
"UNIT RESULT","UNION RESULT","INTERSECT RESULT","EXCEPT RESULT"
};
+const char *pushed_unit_operation_text[4]=
+{
+ "PUSHED UNIT", "PUSHED UNION", "PUSHED INTERSECT", "PUSHED EXCEPT"
+};
+
const char *pushed_derived_text= "PUSHED DERIVED";
const char *pushed_select_text= "PUSHED SELECT";
@@ -575,7 +580,22 @@ uint Explain_union::make_union_table_name(char *buf)
}
-int Explain_union::print_explain(Explain_query *query,
+int Explain_union::print_explain(Explain_query *query,
+ select_result_sink *output,
+ uint8 explain_flags, bool is_analyze)
+{
+ if (is_pushed_down_to_engine)
+ return print_explain_pushed_down(output, explain_flags, is_analyze);
+ else
+ return print_explain_regular(query, output, explain_flags, is_analyze);
+}
+
+/*
+ Prints EXPLAIN plan for a regular UNIT (UNION/EXCEPT/INTERSECT),
+ i.e. UNIT that has not been pushed down to a storage engine
+*/
+
+int Explain_union::print_explain_regular(Explain_query *query,
select_result_sink *output,
uint8 explain_flags,
bool is_analyze)
@@ -592,7 +612,15 @@ int Explain_union::print_explain(Explain_query *query,
}
if (!using_tmp)
+ {
+ /*
+ The union operation may not employ a temporary table, for example,
+ for UNION ALL, in that case the results of the query are sent directly
+ to the output. So there is no actual UNION operation and we don't need
+ to print the line in the EXPLAIN output.
+ */
return 0;
+ }
/* Print a line with "UNIT RESULT" */
List<Item> item_list;
@@ -609,7 +637,7 @@ int Explain_union::print_explain(Explain_query *query,
item_list.push_back(new (mem_root)
Item_string_sys(thd, table_name_buffer, len),
mem_root);
-
+
/* `partitions` column */
if (explain_flags & DESCRIBE_PARTITIONS)
item_list.push_back(item_null, mem_root);
@@ -665,7 +693,6 @@ int Explain_union::print_explain(Explain_query *query,
extra_buf.length()),
mem_root);
- //output->unit.offset_limit_cnt= 0;
if (output->send_data(item_list))
return 1;
@@ -677,9 +704,89 @@ int Explain_union::print_explain(Explain_query *query,
}
-void Explain_union::print_explain_json(Explain_query *query,
+/*
+ Prints EXPLAIN plan for a UNIT (UNION/EXCEPT/INTERSECT) that
+ has been pushed down to a storage engine
+*/
+
+int Explain_union::print_explain_pushed_down(select_result_sink *output,
+ uint8 explain_flags,
+ bool is_analyze)
+{
+ THD *thd= output->thd;
+ MEM_ROOT *mem_root= thd->mem_root;
+ List<Item> item_list;
+ Item *item_null= new (mem_root) Item_null(thd);
+
+ /* `id` column */
+ item_list.push_back(item_null, mem_root);
+
+ /* `select_type` column */
+ push_str(thd, &item_list, fake_select_type);
+
+ /* `table` column */
+ item_list.push_back(item_null, mem_root);
+
+ /* `partitions` column */
+ if (explain_flags & DESCRIBE_PARTITIONS)
+ item_list.push_back(item_null, mem_root);
+
+ /* `type` column */
+ item_list.push_back(item_null, mem_root);
+
+ /* `possible_keys` column */
+ item_list.push_back(item_null, mem_root);
+
+ /* `key` */
+ item_list.push_back(item_null, mem_root);
+
+ /* `key_len` */
+ item_list.push_back(item_null, mem_root);
+
+ /* `ref` */
+ item_list.push_back(item_null, mem_root);
+
+ /* `rows` */
+ item_list.push_back(item_null, mem_root);
+
+ /* `r_rows` */
+ if (is_analyze)
+ item_list.push_back(item_null, mem_root);
+
+ /* `filtered` */
+ if (explain_flags & DESCRIBE_EXTENDED || is_analyze)
+ item_list.push_back(item_null, mem_root);
+
+ /* `r_filtered` */
+ if (is_analyze)
+ item_list.push_back(item_null, mem_root);
+
+ /* `Extra` */
+ item_list.push_back(item_null, mem_root);
+
+ if (output->send_data(item_list))
+ return 1;
+ return 0;
+}
+
+
+void Explain_union::print_explain_json(Explain_query *query,
Json_writer *writer, bool is_analyze)
{
+ if (is_pushed_down_to_engine)
+ print_explain_json_pushed_down(query, writer, is_analyze);
+ else
+ print_explain_json_regular(query, writer, is_analyze);
+}
+
+/*
+ Prints EXPLAIN plan in JSON format for a regular UNIT (UNION/EXCEPT/INTERSECT),
+ i.e. UNIT that has not been pushed down to a storage engine
+*/
+
+void Explain_union::print_explain_json_regular(
+ Explain_query *query, Json_writer *writer, bool is_analyze)
+{
Json_writer_nesting_guard guard(writer);
char table_name_buffer[SAFE_NAME_LEN];
@@ -737,6 +844,30 @@ void Explain_union::print_explain_json(Explain_query *query,
writer->end_object();
}
+/*
+ Prints EXPLAIN plan in JSON format for a UNIT (UNION/EXCEPT/INTERSECT) that
+ has been pushed down to a storage engine
+*/
+
+void Explain_union::print_explain_json_pushed_down(Explain_query *query,
+ Json_writer *writer,
+ bool is_analyze)
+{
+ Json_writer_nesting_guard guard(writer);
+
+ writer->add_member("query_block").start_object();
+
+ if (is_recursive_cte)
+ writer->add_member("recursive_union").start_object();
+ else
+ writer->add_member("union_result").start_object();
+
+ writer->add_member("message").add_str(fake_select_type);
+
+ writer->end_object(); // union_result
+ writer->end_object(); // query_block
+}
+
/*
Print EXPLAINs for all children nodes (i.e. for subqueries)
@@ -1028,6 +1159,9 @@ void Explain_select::print_explain_json(Explain_query *query,
writer->add_member("select_id").add_ll(select_id);
add_linkage(writer);
+ if (cost != 0.0)
+ writer->add_member("cost").add_double(cost);
+
if (is_analyze && time_tracker.get_loops())
{
writer->add_member("r_loops").add_ll(time_tracker.get_loops());
@@ -1371,10 +1505,12 @@ double Explain_table_access::get_r_filtered()
}
-int Explain_table_access::print_explain(select_result_sink *output, uint8 explain_flags,
+int Explain_table_access::print_explain(select_result_sink *output,
+ uint8 explain_flags,
bool is_analyze,
uint select_id, const char *select_type,
- bool using_temporary, bool using_filesort)
+ bool using_temporary,
+ bool using_filesort)
{
THD *thd= output->thd; // note: for SHOW EXPLAIN, this is target thd.
MEM_ROOT *mem_root= thd->mem_root;
@@ -1921,10 +2057,21 @@ void Explain_table_access::print_explain_json(Explain_query *query,
rowid_filter->print_explain_json(query, writer, is_analyze);
}
+ if (loops != 0.0)
+ writer->add_member("loops").add_double(loops);
+
/* r_loops (not present in tabular output) */
if (is_analyze)
{
- writer->add_member("r_loops").add_ll(tracker.get_loops());
+ ha_rows loops= tracker.get_loops();
+ writer->add_member("r_loops").add_ll(loops);
+
+ if (type == JT_EQ_REF) // max one row
+ {
+ ha_rows table_loops= op_tracker.get_loops();
+ if (table_loops != loops)
+ writer->add_member("r_table_loops").add_ll(table_loops);
+ }
}
/* `rows` */
@@ -1950,7 +2097,13 @@ void Explain_table_access::print_explain_json(Explain_query *query,
else
writer->add_null();
}
+ }
+
+ if (cost != 0.0)
+ writer->add_member("cost").add_double(cost);
+ if (is_analyze)
+ {
if (op_tracker.get_loops())
{
double total_time= op_tracker.get_time_ms();
@@ -2050,6 +2203,7 @@ void Explain_table_access::print_explain_json(Explain_query *query,
}
else
writer->add_null();
+
}
}