Permalink
Browse files

Make EXPLAIN FORMAT=JSON be able to show the key that's used for sort…

…ing.

This will be useful for window functions development.
  • Loading branch information...
spetrunia committed Mar 30, 2016
1 parent 9b5951c commit 2078392cc9bb49720ca3949731078af113ae4f43
@@ -490,6 +490,7 @@ ANALYZE
"volatile parameter": "REPLACED",
"having_condition": "(TOP > t2.a)",
"filesort": {
"sort_key": "t2.a",
"r_loops": 1,
"volatile parameter": "REPLACED",
"r_used_priority_queue": false,
@@ -519,6 +520,7 @@ ANALYZE
"r_loops": 1,
"volatile parameter": "REPLACED",
"filesort": {
"sort_key": "t2.a",
"r_loops": 1,
"volatile parameter": "REPLACED",
"r_used_priority_queue": false,
@@ -559,6 +561,7 @@ ANALYZE
"r_loops": 1,
"volatile parameter": "REPLACED",
"filesort": {
"sort_key": "t2.a",
"r_loops": 1,
"volatile parameter": "REPLACED",
"r_used_priority_queue": false,
@@ -680,13 +683,15 @@ ANALYZE
"r_loops": 1,
"volatile parameter": "REPLACED",
"filesort": {
"sort_key": "group_concat(t3.f3 separator ',')",
"r_loops": 1,
"volatile parameter": "REPLACED",
"r_used_priority_queue": false,
"r_output_rows": 0,
"volatile parameter": "REPLACED",
"temporary_table": {
"filesort": {
"sort_key": "(subquery#2)",
"r_loops": 1,
"volatile parameter": "REPLACED",
"r_used_priority_queue": false,
@@ -172,6 +172,7 @@ EXPLAIN
"query_block": {
"select_id": 1,
"filesort": {
"sort_key": "t2.b",
"temporary_table": {
"table": {
"table_name": "t0",
@@ -204,6 +205,7 @@ ANALYZE
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"filesort": {
"sort_key": "t2.b",
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"r_limit": 4,
@@ -256,6 +258,7 @@ EXPLAIN
"select_id": 1,
"read_sorted_file": {
"filesort": {
"sort_key": "t0.a",
"table": {
"table_name": "t0",
"access_type": "ALL",
@@ -289,6 +292,7 @@ ANALYZE
"read_sorted_file": {
"r_rows": 10,
"filesort": {
"sort_key": "t0.a",
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"r_used_priority_queue": false,
@@ -345,6 +349,7 @@ ANALYZE
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"filesort": {
"sort_key": "t2.c",
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"r_used_priority_queue": false,
@@ -454,13 +459,15 @@ ANALYZE
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"filesort": {
"sort_key": "count(distinct t5.b)",
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"r_limit": 1,
"r_used_priority_queue": true,
"r_output_rows": 2,
"temporary_table": {
"filesort": {
"sort_key": "t5.a",
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"r_used_priority_queue": false,
@@ -510,8 +517,10 @@ EXPLAIN
"query_block": {
"select_id": 1,
"filesort": {
"sort_key": "count(distinct t5.b)",
"temporary_table": {
"filesort": {
"sort_key": "t5.a",
"temporary_table": {
"table": {
"table_name": "t6",
@@ -486,6 +486,7 @@ EXPLAIN
"query_block": {
"select_id": 2,
"filesort": {
"sort_key": "t1.a",
"temporary_table": {
"table": {
"table_name": "t1",
@@ -529,6 +530,7 @@ EXPLAIN
"query_block": {
"select_id": 2,
"filesort": {
"sort_key": "t1.a",
"temporary_table": {
"table": {
"table_name": "t1",
@@ -1129,6 +1131,7 @@ EXPLAIN
"select_id": 1,
"having_condition": "(TOP > t2.a)",
"filesort": {
"sort_key": "t2.a",
"temporary_table": {
"table": {
"table_name": "t2",
@@ -1147,6 +1150,7 @@ EXPLAIN
"query_block": {
"select_id": 1,
"filesort": {
"sort_key": "t2.a",
"temporary_table": {
"table": {
"table_name": "t2",
@@ -1176,6 +1180,7 @@ EXPLAIN
"query_block": {
"select_id": 1,
"filesort": {
"sort_key": "t2.a",
"temporary_table": {
"table": {
"table_name": "t2",
View
@@ -1436,6 +1436,7 @@ EXPLAIN
"query_block": {
"select_id": 1,
"filesort": {
"sort_key": "t1.a",
"window_functions_computation": {
"temporary_table": {
"table": {
@@ -1488,6 +1489,7 @@ EXPLAIN
"select_id": 1,
"having_condition": "(MX in (3,5,7))",
"filesort": {
"sort_key": "t1.b",
"window_functions_computation": {
"temporary_table": {
"table": {
View
@@ -30,6 +30,7 @@ const char * STR_IMPOSSIBLE_WHERE= "Impossible WHERE";
const char * STR_NO_ROWS_AFTER_PRUNING= "No matching rows after partition pruning";
static void write_item(Json_writer *writer, Item *item);
static void append_item_to_str(String *out, Item *item);
Explain_query::Explain_query(THD *thd_arg, MEM_ROOT *root) :
mem_root(root), upd_del_plan(NULL), insert_plan(NULL),
@@ -877,8 +878,7 @@ void Explain_select::print_explain_json(Explain_query *query,
case AGGR_OP_FILESORT:
{
writer->add_member("filesort").start_object();
if (is_analyze)
((Explain_aggr_filesort*)node)->tracker->print_json_members(writer);
((Explain_aggr_filesort*)node)->print_json_members(writer, is_analyze);
break;
}
case AGGR_OP_REMOVE_DUPLICATES:
@@ -905,6 +905,41 @@ void Explain_select::print_explain_json(Explain_query *query,
writer->end_object();
}
void Explain_aggr_filesort::init(THD *thd, Filesort *filesort)
{
for (ORDER *ord= filesort->order; ord; ord= ord->next)
{
sort_items.push_back(ord->item[0], thd->mem_root);
}
filesort->tracker= &tracker;
}
void Explain_aggr_filesort::print_json_members(Json_writer *writer,
bool is_analyze)
{
char item_buf[256];
String str(item_buf, sizeof(item_buf), &my_charset_bin);
str.length(0);
List_iterator_fast<Item> it(sort_items);
Item *item;
bool first= true;
while ((item= it++))
{
if (first)
first= false;
else
{
str.append(", ");
}
append_item_to_str(&str, item);
}
writer->add_member("sort_key").add_str(str.c_ptr_safe());
if (is_analyze)
tracker.print_json_members(writer);
}
void Explain_basic_join::print_explain_json(Explain_query *query,
Json_writer *writer,
@@ -1222,7 +1257,7 @@ int Explain_table_access::print_explain(select_result_sink *output, uint8 explai
extra_buf.append(STRING_WITH_LEN("Using temporary"));
}
if (using_filesort || this->using_filesort)
if (using_filesort || this->pre_join_sort)
{
if (first)
first= false;
@@ -1282,6 +1317,15 @@ static void write_item(Json_writer *writer, Item *item)
writer->add_str(str.c_ptr_safe());
}
static void append_item_to_str(String *out, Item *item)
{
THD *thd= current_thd;
ulonglong save_option_bits= thd->variables.option_bits;
thd->variables.option_bits &= ~OPTION_QUOTE_SHOW_CREATE;
item->print(out, QT_EXPLAIN);
thd->variables.option_bits= save_option_bits;
}
void Explain_table_access::tag_to_json(Json_writer *writer, enum explain_extra_tag tag)
{
@@ -1409,23 +1453,14 @@ void add_json_keyset(Json_writer *writer, const char *elem_name,
print_json_array(writer, elem_name, *keyset);
}
/*
@param fs_tracker Normally NULL. When not NULL, it means that the join tab
used filesort to pre-sort the data. Then, sorted data
was read and the rest of the join was executed.
@note
EXPLAIN command will check whether fs_tracker is present, but it can't use
any value from fs_tracker (these are only valid for ANALYZE).
*/
void Explain_table_access::print_explain_json(Explain_query *query,
Json_writer *writer,
bool is_analyze)
{
Json_writer_nesting_guard guard(writer);
if (using_filesort)
if (pre_join_sort)
{
/* filesort was invoked on this join tab before doing the join with the rest */
writer->add_member("read_sorted_file").start_object();
@@ -1452,9 +1487,7 @@ void Explain_table_access::print_explain_json(Explain_query *query,
}
}
writer->add_member("filesort").start_object();
if (is_analyze)
fs_tracker->print_json_members(writer);
pre_join_sort->print_json_members(writer, is_analyze);
}
if (bka_type.is_using_jbuf())
@@ -1532,11 +1565,11 @@ void Explain_table_access::print_explain_json(Explain_query *query,
if (is_analyze)
{
writer->add_member("r_rows");
if (fs_tracker)
if (pre_join_sort)
{
/* Get r_rows value from filesort */
if (fs_tracker->get_r_loops())
writer->add_double(fs_tracker->get_avg_examined_rows());
if (pre_join_sort->tracker.get_r_loops())
writer->add_double(pre_join_sort->tracker.get_avg_examined_rows());
else
writer->add_null();
}
@@ -1563,11 +1596,11 @@ void Explain_table_access::print_explain_json(Explain_query *query,
if (is_analyze)
{
writer->add_member("r_filtered");
if (fs_tracker)
if (pre_join_sort)
{
/* Get r_filtered value from filesort */
if (fs_tracker->get_r_loops())
writer->add_double(fs_tracker->get_r_filtered());
if (pre_join_sort->tracker.get_r_loops())
writer->add_double(pre_join_sort->tracker.get_r_filtered());
else
writer->add_null();
}
@@ -1645,7 +1678,7 @@ void Explain_table_access::print_explain_json(Explain_query *query,
writer->end_object();
}
if (using_filesort)
if (pre_join_sort)
{
writer->end_object(); // filesort
writer->end_object(); // read_sorted_file
View
@@ -281,9 +281,18 @@ class Explain_aggr_node : public Sql_alloc
class Explain_aggr_filesort : public Explain_aggr_node
{
List<Item> sort_items;
public:
enum_explain_aggr_node_type get_type() { return AGGR_OP_FILESORT; }
Filesort_tracker *tracker;
Filesort_tracker tracker;
Explain_aggr_filesort(bool is_analyze) : tracker(is_analyze)
{
child= NULL;
}
void init(THD* thd, Filesort *filesort);
void print_json_members(Json_writer *writer, bool is_analyze);
};
class Explain_aggr_tmp_table : public Explain_aggr_node
@@ -663,8 +672,7 @@ class Explain_table_access : public Sql_alloc
cache_cond(NULL),
pushed_index_cond(NULL),
sjm_nest(NULL),
using_filesort(false),
fs_tracker(NULL)
pre_join_sort(NULL)
{}
~Explain_table_access() { delete sjm_nest; }
@@ -757,9 +765,13 @@ class Explain_table_access : public Sql_alloc
Item *pushed_index_cond;
Explain_basic_join *sjm_nest;
bool using_filesort;
Filesort_tracker *fs_tracker;
/*
This describes a possible filesort() call that is done before doing the
join operation.
*/
Explain_aggr_filesort *pre_join_sort;
/* ANALYZE members */
/* Tracker for reading the table */
Oops, something went wrong.

0 comments on commit 2078392

Please sign in to comment.