mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
Make EXPLAIN FORMAT=JSON be able to show the key that's used for sorting.
This will be useful for window functions development.
This commit is contained in:
@ -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,6 +683,7 @@ 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,
|
||||
@ -687,6 +691,7 @@ ANALYZE
|
||||
"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,6 +459,7 @@ 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,
|
||||
@ -461,6 +467,7 @@ ANALYZE
|
||||
"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",
|
||||
|
@ -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": {
|
||||
|
@ -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,15 +1453,6 @@ 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,
|
||||
@ -1425,7 +1460,7 @@ void Explain_table_access::print_explain_json(Explain_query *query,
|
||||
{
|
||||
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
|
||||
|
@ -281,9 +281,18 @@ public:
|
||||
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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 */
|
||||
|
@ -23746,7 +23746,6 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta,
|
||||
explain_plan= eta;
|
||||
eta->key.clear();
|
||||
eta->quick_info= NULL;
|
||||
eta->using_filesort= false;
|
||||
|
||||
SQL_SELECT *tab_select;
|
||||
/*
|
||||
@ -23758,9 +23757,8 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta,
|
||||
|
||||
if (filesort)
|
||||
{
|
||||
eta->using_filesort= true; // This fixes EXPLAIN
|
||||
eta->fs_tracker= filesort->tracker=
|
||||
new Filesort_tracker(thd->lex->analyze_stmt);
|
||||
eta->pre_join_sort= new Explain_aggr_filesort(thd->lex->analyze_stmt);
|
||||
eta->pre_join_sort->init(thd, filesort);
|
||||
}
|
||||
|
||||
tracker= &eta->tracker;
|
||||
@ -24201,9 +24199,9 @@ void save_agg_explain_data(JOIN *join, Explain_select *xpl_sel)
|
||||
|
||||
if (join_tab->filesort)
|
||||
{
|
||||
Explain_aggr_filesort *eaf = new Explain_aggr_filesort;
|
||||
eaf->tracker= new Filesort_tracker(join->thd->lex->analyze_stmt);
|
||||
join_tab->filesort->tracker= eaf->tracker;
|
||||
bool is_analyze= join->thd->lex->analyze_stmt;
|
||||
Explain_aggr_filesort *eaf = new Explain_aggr_filesort(is_analyze);
|
||||
eaf->init(join->thd, join_tab->filesort);
|
||||
|
||||
prev_node= node;
|
||||
node= eaf;
|
||||
|
Reference in New Issue
Block a user