1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

MDEV-8646: Re-engineer the code for post-join operations

- Make EXPLAIN code use the post-join operations
- Remove Sort_and_group_tracker that was used for that purpose
This commit is contained in:
Sergei Petrunia
2016-03-28 12:02:56 +03:00
parent 24cd633fd8
commit 44fdb56c97
16 changed files with 224 additions and 494 deletions

View File

@@ -685,13 +685,13 @@ ANALYZE
"r_used_priority_queue": false, "r_used_priority_queue": false,
"r_output_rows": 0, "r_output_rows": 0,
"volatile parameter": "REPLACED", "volatile parameter": "REPLACED",
"temporary_table": {
"filesort": { "filesort": {
"r_loops": 1, "r_loops": 1,
"volatile parameter": "REPLACED", "volatile parameter": "REPLACED",
"r_used_priority_queue": false, "r_used_priority_queue": false,
"r_output_rows": 0, "r_output_rows": 0,
"volatile parameter": "REPLACED", "volatile parameter": "REPLACED",
"temporary_table": {
"temporary_table": { "temporary_table": {
"table": { "table": {
"table_name": "t2", "table_name": "t2",

View File

@@ -173,7 +173,6 @@ EXPLAIN
"select_id": 1, "select_id": 1,
"filesort": { "filesort": {
"temporary_table": { "temporary_table": {
"function": "buffer",
"table": { "table": {
"table_name": "t0", "table_name": "t0",
"access_type": "ALL", "access_type": "ALL",
@@ -460,13 +459,13 @@ ANALYZE
"r_limit": 1, "r_limit": 1,
"r_used_priority_queue": true, "r_used_priority_queue": true,
"r_output_rows": 2, "r_output_rows": 2,
"temporary_table": {
"filesort": { "filesort": {
"r_loops": 1, "r_loops": 1,
"r_total_time_ms": "REPLACED", "r_total_time_ms": "REPLACED",
"r_used_priority_queue": false, "r_used_priority_queue": false,
"r_output_rows": 6, "r_output_rows": 6,
"r_buffer_size": "REPLACED", "r_buffer_size": "REPLACED",
"temporary_table": {
"temporary_table": { "temporary_table": {
"table": { "table": {
"table_name": "t6", "table_name": "t6",
@@ -512,7 +511,8 @@ EXPLAIN
"select_id": 1, "select_id": 1,
"filesort": { "filesort": {
"temporary_table": { "temporary_table": {
"function": "buffer", "filesort": {
"temporary_table": {
"table": { "table": {
"table_name": "t6", "table_name": "t6",
"access_type": "ALL", "access_type": "ALL",
@@ -535,6 +535,8 @@ EXPLAIN
} }
} }
} }
}
}
} }
drop table t5,t6,t7; drop table t5,t6,t7;
drop table t3; drop table t3;

View File

@@ -231,8 +231,8 @@ CREATE VIEW v1 AS SELECT a, MIN(b) AS b FROM t2 GROUP BY a;
EXPLAIN EXPLAIN
SELECT * FROM v1, t1 WHERE v1.b=t1.a ORDER BY v1.a; SELECT * FROM v1, t1 WHERE v1.b=t1.a ORDER BY v1.a;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 system NULL NULL NULL NULL 1 Using filesort 1 PRIMARY t1 system NULL NULL NULL NULL 1
1 PRIMARY <derived2> ref key0 key0 5 const 1 Using where 1 PRIMARY <derived2> ref key0 key0 5 const 1 Using where; Using filesort
2 DERIVED t2 ALL NULL NULL NULL NULL 10 Using temporary; Using filesort 2 DERIVED t2 ALL NULL NULL NULL NULL 10 Using temporary; Using filesort
SELECT * FROM v1, t1 WHERE v1.b=t1.a ORDER BY v1.a; SELECT * FROM v1, t1 WHERE v1.b=t1.a ORDER BY v1.a;
a b a a b a

View File

@@ -487,7 +487,6 @@ EXPLAIN
"select_id": 2, "select_id": 2,
"filesort": { "filesort": {
"temporary_table": { "temporary_table": {
"function": "buffer",
"table": { "table": {
"table_name": "t1", "table_name": "t1",
"access_type": "ALL", "access_type": "ALL",
@@ -531,7 +530,6 @@ EXPLAIN
"select_id": 2, "select_id": 2,
"filesort": { "filesort": {
"temporary_table": { "temporary_table": {
"function": "buffer",
"table": { "table": {
"table_name": "t1", "table_name": "t1",
"access_type": "ALL", "access_type": "ALL",
@@ -576,7 +574,6 @@ EXPLAIN
"query_block": { "query_block": {
"select_id": 2, "select_id": 2,
"temporary_table": { "temporary_table": {
"function": "buffer",
"table": { "table": {
"table_name": "t1", "table_name": "t1",
"access_type": "ALL", "access_type": "ALL",
@@ -1133,7 +1130,6 @@ EXPLAIN
"having_condition": "(TOP > t2.a)", "having_condition": "(TOP > t2.a)",
"filesort": { "filesort": {
"temporary_table": { "temporary_table": {
"function": "buffer",
"table": { "table": {
"table_name": "t2", "table_name": "t2",
"access_type": "ALL", "access_type": "ALL",
@@ -1152,7 +1148,6 @@ EXPLAIN
"select_id": 1, "select_id": 1,
"filesort": { "filesort": {
"temporary_table": { "temporary_table": {
"function": "buffer",
"table": { "table": {
"table_name": "t2", "table_name": "t2",
"access_type": "ALL", "access_type": "ALL",
@@ -1182,7 +1177,6 @@ EXPLAIN
"select_id": 1, "select_id": 1,
"filesort": { "filesort": {
"temporary_table": { "temporary_table": {
"function": "buffer",
"table": { "table": {
"table_name": "t2", "table_name": "t2",
"access_type": "ALL", "access_type": "ALL",
@@ -1380,7 +1374,6 @@ EXPLAIN
"query_block": { "query_block": {
"select_id": 1, "select_id": 1,
"temporary_table": { "temporary_table": {
"function": "buffer",
"table": { "table": {
"table_name": "t1", "table_name": "t1",
"access_type": "ALL", "access_type": "ALL",

View File

@@ -5412,9 +5412,9 @@ WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND
t2.a BETWEEN 4 and 5 t2.a BETWEEN 4 and 5
ORDER BY t2.b; ORDER BY t2.b;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 system NULL NULL NULL NULL 1 Using filesort 1 PRIMARY t1 system NULL NULL NULL NULL 1
1 PRIMARY t3 system NULL NULL NULL NULL 1 1 PRIMARY t3 system NULL NULL NULL NULL 1
1 PRIMARY t2 range a,c a 5 NULL 1 Using index condition; Using where 1 PRIMARY t2 range a,c a 5 NULL 1 Using index condition; Using where; Using filesort
1 PRIMARY t4 ref c c 5 test.t2.c 2 Using where; Start temporary; End temporary 1 PRIMARY t4 ref c c 5 test.t2.c 2 Using where; Start temporary; End temporary
SELECT * FROM t1,t2 SELECT * FROM t1,t2
WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND

View File

@@ -1289,8 +1289,8 @@ SELECT t1.a, COUNT( t2.b ), SUM( t2.b ), MAX( t2.b )
FROM t1 JOIN t2 USING( a ) FROM t1 JOIN t2 USING( a )
GROUP BY t1.a WITH ROLLUP; GROUP BY t1.a WITH ROLLUP;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1 Using filesort 1 SIMPLE t1 system NULL NULL NULL NULL 1
1 SIMPLE t2 ALL NULL NULL NULL NULL 5 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 5 Using where; Using filesort
SELECT t1.a, COUNT( t2.b ), SUM( t2.b ), MAX( t2.b ) SELECT t1.a, COUNT( t2.b ), SUM( t2.b ), MAX( t2.b )
FROM t1 JOIN t2 USING( a ) FROM t1 JOIN t2 USING( a )
GROUP BY t1.a WITH ROLLUP; GROUP BY t1.a WITH ROLLUP;
@@ -1429,8 +1429,8 @@ EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1
WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL
GROUP BY t2.f1, t2.f2; GROUP BY t2.f1, t2.f2;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system PRIMARY NULL NULL NULL 1 Using filesort 1 SIMPLE t1 system PRIMARY NULL NULL NULL 1
1 SIMPLE t2 ref PRIMARY PRIMARY 4 const 1 Using where; Using index 1 SIMPLE t2 ref PRIMARY PRIMARY 4 const 1 Using where; Using index; Using filesort
SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1 SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1
WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL
GROUP BY t2.f1, t2.f2; GROUP BY t2.f1, t2.f2;
@@ -1846,8 +1846,8 @@ EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1
WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL
GROUP BY t2.f1, t2.f2; GROUP BY t2.f1, t2.f2;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system PRIMARY NULL NULL NULL 1 Using filesort 1 SIMPLE t1 system PRIMARY NULL NULL NULL 1
1 SIMPLE t2 ref PRIMARY PRIMARY 4 const 1 Using where; Using index 1 SIMPLE t2 ref PRIMARY PRIMARY 4 const 1 Using where; Using index; Using filesort
SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1 SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1
WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL
GROUP BY t2.f1, t2.f2; GROUP BY t2.f1, t2.f2;

View File

@@ -1300,8 +1300,8 @@ SELECT t1.a, COUNT( t2.b ), SUM( t2.b ), MAX( t2.b )
FROM t1 JOIN t2 USING( a ) FROM t1 JOIN t2 USING( a )
GROUP BY t1.a WITH ROLLUP; GROUP BY t1.a WITH ROLLUP;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1 Using filesort 1 SIMPLE t1 system NULL NULL NULL NULL 1
1 SIMPLE t2 ALL NULL NULL NULL NULL 5 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 5 Using where; Using filesort
SELECT t1.a, COUNT( t2.b ), SUM( t2.b ), MAX( t2.b ) SELECT t1.a, COUNT( t2.b ), SUM( t2.b ), MAX( t2.b )
FROM t1 JOIN t2 USING( a ) FROM t1 JOIN t2 USING( a )
GROUP BY t1.a WITH ROLLUP; GROUP BY t1.a WITH ROLLUP;
@@ -1440,8 +1440,8 @@ EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1
WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL
GROUP BY t2.f1, t2.f2; GROUP BY t2.f1, t2.f2;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system PRIMARY NULL NULL NULL 1 Using filesort 1 SIMPLE t1 system PRIMARY NULL NULL NULL 1
1 SIMPLE t2 ref PRIMARY PRIMARY 4 const 1 Using where; Using index 1 SIMPLE t2 ref PRIMARY PRIMARY 4 const 1 Using where; Using index; Using filesort
SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1 SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1
WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL
GROUP BY t2.f1, t2.f2; GROUP BY t2.f1, t2.f2;
@@ -1857,8 +1857,8 @@ EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1
WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL
GROUP BY t2.f1, t2.f2; GROUP BY t2.f1, t2.f2;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system PRIMARY NULL NULL NULL 1 Using filesort 1 SIMPLE t1 system PRIMARY NULL NULL NULL 1
1 SIMPLE t2 ref PRIMARY PRIMARY 4 const 1 Using where; Using index 1 SIMPLE t2 ref PRIMARY PRIMARY 4 const 1 Using where; Using index; Using filesort
SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1 SELECT * FROM t1 LEFT JOIN t2 ON t2.f1 = t1.f1
WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL
GROUP BY t2.f1, t2.f2; GROUP BY t2.f1, t2.f2;

View File

@@ -7,8 +7,8 @@ explain select 1 from
(select f2, f3, val, count(id) from t4 join t2 left join t3 on 0) top (select f2, f3, val, count(id) from t4 join t2 left join t3 on 0) top
join t1 on f1 = f3 where f3 = 'aaaa' order by val; join t1 on f1 = f3 where f3 = 'aaaa' order by val;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 const PRIMARY PRIMARY 12 const 1 Using index; Using filesort 1 PRIMARY t1 const PRIMARY PRIMARY 12 const 1 Using index
1 PRIMARY <derived2> ref key0 key0 13 const 0 Using where 1 PRIMARY <derived2> ref key0 key0 13 const 0 Using where; Using filesort
2 DERIVED t4 ALL NULL NULL NULL NULL 1 2 DERIVED t4 ALL NULL NULL NULL NULL 1
2 DERIVED t2 ALL NULL NULL NULL NULL 1 Using join buffer (flat, BNL join) 2 DERIVED t2 ALL NULL NULL NULL NULL 1 Using join buffer (flat, BNL join)
2 DERIVED t3 ALL NULL NULL NULL NULL 1 Using where; Using join buffer (incremental, BNL join) 2 DERIVED t3 ALL NULL NULL NULL NULL 1 Using where; Using join buffer (incremental, BNL join)

View File

@@ -2003,8 +2003,8 @@ FROM t2 JOIN t3 ON t3.f4 = t2.f4
WHERE t3.f1 = 8 WHERE t3.f1 = 8
GROUP BY 1, 2; GROUP BY 1, 2;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 system NULL NULL NULL NULL 1 Using filesort 1 PRIMARY t3 system NULL NULL NULL NULL 1
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; Using filesort
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE 2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
3 MATERIALIZED NULL NULL NULL NULL NULL NULL NULL no matching row in const table 3 MATERIALIZED NULL NULL NULL NULL NULL NULL NULL no matching row in const table
PREPARE st1 FROM " PREPARE st1 FROM "

View File

@@ -50,6 +50,8 @@ public:
/** true means we are using Priority Queue for order by with limit. */ /** true means we are using Priority Queue for order by with limit. */
bool using_pq; bool using_pq;
Filesort_tracker *tracker;
Filesort(ORDER *order_arg, ha_rows limit_arg, SQL_SELECT *select_arg): Filesort(ORDER *order_arg, ha_rows limit_arg, SQL_SELECT *select_arg):
order(order_arg), order(order_arg),
limit(limit_arg), limit(limit_arg),

View File

@@ -69,75 +69,3 @@ void Filesort_tracker::print_json_members(Json_writer *writer)
} }
} }
/*
Report that we are doing a filesort.
@return
Tracker object to be used with filesort
*/
Filesort_tracker *Sort_and_group_tracker::report_sorting(THD *thd)
{
DBUG_ASSERT(cur_action < MAX_QEP_ACTIONS);
if (total_actions)
{
/* This is not the first execution. Check */
if (qep_actions[cur_action] != EXPL_ACTION_FILESORT)
{
varied_executions= true;
cur_action++;
if (!dummy_fsort_tracker)
dummy_fsort_tracker= new (thd->mem_root) Filesort_tracker(is_analyze);
return dummy_fsort_tracker;
}
return qep_actions_data[cur_action++].filesort_tracker;
}
Filesort_tracker *fs_tracker= new(thd->mem_root)Filesort_tracker(is_analyze);
qep_actions_data[cur_action].filesort_tracker= fs_tracker;
qep_actions[cur_action++]= EXPL_ACTION_FILESORT;
return fs_tracker;
}
void Sort_and_group_tracker::report_tmp_table(TABLE *tbl)
{
DBUG_ASSERT(cur_action < MAX_QEP_ACTIONS);
if (total_actions)
{
/* This is not the first execution. Check if the steps match. */
// todo: should also check that tmp.table kinds are the same.
if (qep_actions[cur_action] != EXPL_ACTION_TEMPTABLE)
varied_executions= true;
}
if (!varied_executions)
{
qep_actions[cur_action]= EXPL_ACTION_TEMPTABLE;
// qep_actions_data[cur_action]= ....
}
cur_action++;
}
void Sort_and_group_tracker::report_duplicate_removal()
{
DBUG_ASSERT(cur_action < MAX_QEP_ACTIONS);
if (total_actions)
{
/* This is not the first execution. Check if the steps match. */
if (qep_actions[cur_action] != EXPL_ACTION_REMOVE_DUPS)
varied_executions= true;
}
if (!varied_executions)
{
qep_actions[cur_action]= EXPL_ACTION_REMOVE_DUPS;
}
cur_action++;
}

View File

@@ -284,174 +284,3 @@ private:
ulonglong sort_buffer_size; ulonglong sort_buffer_size;
}; };
typedef enum
{
EXPL_NO_TMP_TABLE=0,
EXPL_TMP_TABLE_BUFFER,
EXPL_TMP_TABLE_GROUP,
EXPL_TMP_TABLE_DISTINCT
} enum_tmp_table_use;
typedef enum
{
EXPL_ACTION_EOF, /* not-an-action */
EXPL_ACTION_FILESORT,
EXPL_ACTION_TEMPTABLE,
EXPL_ACTION_REMOVE_DUPS,
} enum_qep_action;
/*
This is to track how a JOIN object has resolved ORDER/GROUP BY/DISTINCT
We are not tied to the query plan at all, because query plan does not have
sufficient information. *A lot* of decisions about ordering/grouping are
made at very late stages (in JOIN::exec, JOIN::init_execution, in
create_sort_index and even in create_tmp_table).
The idea is that operations that happen during select execution will report
themselves. We have these operations:
- Sorting with filesort()
- Duplicate row removal (the one done by remove_duplicates()).
- Use of temporary table to buffer the result.
There is also "Selection" operation, done by do_select(). It reads rows,
there are several distinct cases:
1. doing the join operation on the base tables
2. reading the temporary table
3. reading the filesort output
it would be nice to build execution graph, e.g.
Select(JOIN op) -> temp.table -> filesort -> Select(filesort result)
the problem is that there is no way to tell what a do_select() call will do.
Our solution is not to have explicit selection operations. We make these
assumptions about the query plan:
- Select(JOIN op) is the first operation in the query plan
- Unless the first recorded operation is filesort(). filesort() is unable
read result of a select, so when we find it first, the query plan is:
filesort(first join table) -> Select(JOIN op) -> ...
the other popular query plan is:
Select (JOIN op) -> temp.table -> filesort() -> ...
///TODO: handle repeated execution with subselects!
*/
class Sort_and_group_tracker : public Sql_alloc
{
enum { MAX_QEP_ACTIONS = 5 };
/* Query actions in the order they were made. */
enum_qep_action qep_actions[MAX_QEP_ACTIONS];
/* Number for the next action */
int cur_action;
/*
Non-zero means there was already an execution which had
#total_actions actions
*/
int total_actions;
int get_n_actions()
{
return total_actions? total_actions: cur_action;
}
/*
TRUE<=>there were executions which took different sort/buffer/de-duplicate
routes. The counter values are not meaningful.
*/
bool varied_executions;
/* Details about query actions */
union
{
Filesort_tracker *filesort_tracker;
enum_tmp_table_use tmp_table;
}
qep_actions_data[MAX_QEP_ACTIONS];
Filesort_tracker *dummy_fsort_tracker;
bool is_analyze;
public:
Sort_and_group_tracker(bool is_analyze_arg) :
cur_action(0), total_actions(0), varied_executions(false),
dummy_fsort_tracker(NULL),
is_analyze(is_analyze_arg)
{}
/*************** Reporting interface ***************/
/* Report that join execution is started */
void report_join_start()
{
if (!total_actions && cur_action != 0)
{
/* This is a second execution */
total_actions= cur_action;
}
cur_action= 0;
}
/*
Report that a temporary table is created. The next step is to write to the
this tmp. table
*/
void report_tmp_table(TABLE *tbl);
/*
Report that we are doing a filesort.
@return
Tracker object to be used with filesort
*/
Filesort_tracker *report_sorting(THD *thd);
/*
Report that remove_duplicates() is invoked [on a temp. table].
We don't collect any statistics on this operation, yet.
*/
void report_duplicate_removal();
friend class Iterator;
/*************** Statistics retrieval interface ***************/
bool had_varied_executions() { return varied_executions; }
class Iterator
{
Sort_and_group_tracker *owner;
int idx;
public:
Iterator(Sort_and_group_tracker *owner_arg) :
owner(owner_arg), idx(owner_arg->get_n_actions() - 1)
{}
enum_qep_action get_next(Filesort_tracker **tracker/*,
enum_tmp_table_use *tmp_table_use*/)
{
/* Walk back through the array... */
if (idx < 0)
return EXPL_ACTION_EOF;
switch (owner->qep_actions[idx])
{
case EXPL_ACTION_FILESORT:
*tracker= owner->qep_actions_data[idx].filesort_tracker;
break;
case EXPL_ACTION_TEMPTABLE:
//*tmp_table_use= tmp_table_kind[tmp_table_idx++];
break;
default:
break;
}
return owner->qep_actions[idx--];
}
bool is_last_element() { return idx == -1; }
};
};

View File

@@ -697,14 +697,6 @@ bool Explain_node::print_explain_json_cache(Json_writer *writer,
} }
#if 0
void Explain_select::replace_table(uint idx, Explain_table_access *new_tab)
{
delete join_tabs[idx];
join_tabs[idx]= new_tab;
}
#endif
Explain_basic_join::~Explain_basic_join() Explain_basic_join::~Explain_basic_join()
{ {
if (join_tabs) if (join_tabs)
@@ -755,35 +747,23 @@ int Explain_select::print_explain(Explain_query *query,
} }
else else
{ {
bool using_tmp; bool using_tmp= false;
bool using_fs; bool using_fs= false;
if (is_analyze) for (Explain_aggr_node *node= aggr_tree; node; node= node->child)
{ {
/* switch (node->get_type())
Get the data about "Using temporary; Using filesort" from execution
tracking system.
*/
using_tmp= false;
using_fs= false;
Sort_and_group_tracker::Iterator iter(&ops_tracker);
enum_qep_action action;
Filesort_tracker *dummy;
while ((action= iter.get_next(&dummy)) != EXPL_ACTION_EOF)
{ {
if (action == EXPL_ACTION_FILESORT) case AGGR_OP_TEMP_TABLE:
using_fs= true;
else if (action == EXPL_ACTION_TEMPTABLE)
using_tmp= true; using_tmp= true;
break;
case AGGR_OP_FILESORT:
using_fs= true;
break;
default:
break;
} }
} }
else
{
/* Use imprecise "estimates" we got with the query plan */
using_tmp= using_temporary;
using_fs= using_filesort;
}
for (uint i=0; i< n_join_tabs; i++) for (uint i=0; i< n_join_tabs; i++)
{ {
@@ -877,88 +857,34 @@ void Explain_select::print_explain_json(Explain_query *query,
} }
} }
Filesort_tracker *first_table_sort= NULL;
bool first_table_sort_used= false;
int started_objects= 0; int started_objects= 0;
if (is_analyze) Explain_aggr_node *node= aggr_tree;
{
/* ANALYZE has collected this part of query plan independently */
if (ops_tracker.had_varied_executions())
{
writer->add_member("varied-sort-and-tmp").start_object();
started_objects++;
}
else
{
Sort_and_group_tracker::Iterator iter(&ops_tracker);
enum_qep_action action;
Filesort_tracker *fs_tracker;
while ((action= iter.get_next(&fs_tracker)) != EXPL_ACTION_EOF) for (; node; node= node->child)
{ {
if (action == EXPL_ACTION_FILESORT) switch (node->get_type())
{ {
if (iter.is_last_element()) case AGGR_OP_TEMP_TABLE:
writer->add_member("temporary_table").start_object();
break;
case AGGR_OP_FILESORT:
{ {
first_table_sort= fs_tracker; writer->add_member("filesort").start_object();
if (is_analyze)
((Explain_aggr_filesort*)node)->tracker->print_json_members(writer);
break; break;
} }
writer->add_member("filesort").start_object(); case AGGR_OP_REMOVE_DUPLICATES:
started_objects++;
fs_tracker->print_json_members(writer);
}
else if (action == EXPL_ACTION_TEMPTABLE)
{
writer->add_member("temporary_table").start_object();
started_objects++;
/*
if (tmp == EXPL_TMP_TABLE_BUFFER)
func= "buffer";
else if (tmp == EXPL_TMP_TABLE_GROUP)
func= "group-by";
else
func= "distinct";
writer->add_member("function").add_str(func);
*/
}
else if (action == EXPL_ACTION_REMOVE_DUPS)
{
writer->add_member("duplicate_removal").start_object(); writer->add_member("duplicate_removal").start_object();
started_objects++; break;
} default:
else
DBUG_ASSERT(0); DBUG_ASSERT(0);
} }
}
if (first_table_sort)
first_table_sort_used= true;
}
else
{
/* This is just EXPLAIN. Try to produce something meaningful */
if (using_temporary)
{
started_objects= 1;
if (using_filesort)
{
started_objects++; started_objects++;
writer->add_member("filesort").start_object();
}
writer->add_member("temporary_table").start_object();
writer->add_member("function").add_str("buffer");
}
else
{
if (using_filesort)
first_table_sort_used= true;
}
} }
Explain_basic_join::print_explain_json_interns(query, writer, is_analyze, Explain_basic_join::print_explain_json_interns(query, writer, is_analyze);
first_table_sort,
first_table_sort_used);
for (;started_objects; started_objects--) for (;started_objects; started_objects--)
writer->end_object(); writer->end_object();
@@ -978,7 +904,7 @@ void Explain_basic_join::print_explain_json(Explain_query *query,
writer->add_member("query_block").start_object(); writer->add_member("query_block").start_object();
writer->add_member("select_id").add_ll(select_id); writer->add_member("select_id").add_ll(select_id);
print_explain_json_interns(query, writer, is_analyze, NULL, false); print_explain_json_interns(query, writer, is_analyze);
writer->end_object(); writer->end_object();
} }
@@ -987,9 +913,7 @@ void Explain_basic_join::print_explain_json(Explain_query *query,
void Explain_basic_join:: void Explain_basic_join::
print_explain_json_interns(Explain_query *query, print_explain_json_interns(Explain_query *query,
Json_writer *writer, Json_writer *writer,
bool is_analyze, bool is_analyze)
Filesort_tracker *first_table_sort,
bool first_table_sort_used)
{ {
Json_writer_nesting_guard guard(writer); Json_writer_nesting_guard guard(writer);
for (uint i=0; i< n_join_tabs; i++) for (uint i=0; i< n_join_tabs; i++)
@@ -997,12 +921,7 @@ print_explain_json_interns(Explain_query *query,
if (join_tabs[i]->start_dups_weedout) if (join_tabs[i]->start_dups_weedout)
writer->add_member("duplicates_removal").start_object(); writer->add_member("duplicates_removal").start_object();
join_tabs[i]->print_explain_json(query, writer, is_analyze, join_tabs[i]->print_explain_json(query, writer, is_analyze);
first_table_sort,
first_table_sort_used);
first_table_sort= NULL;
first_table_sort_used= false;
if (join_tabs[i]->end_dups_weedout) if (join_tabs[i]->end_dups_weedout)
writer->end_object(); writer->end_object();
@@ -1294,7 +1213,7 @@ int Explain_table_access::print_explain(select_result_sink *output, uint8 explai
extra_buf.append(STRING_WITH_LEN("Using temporary")); extra_buf.append(STRING_WITH_LEN("Using temporary"));
} }
if (using_filesort) if (using_filesort || this->using_filesort)
{ {
if (first) if (first)
first= false; first= false;
@@ -1493,13 +1412,11 @@ void add_json_keyset(Json_writer *writer, const char *elem_name,
void Explain_table_access::print_explain_json(Explain_query *query, void Explain_table_access::print_explain_json(Explain_query *query,
Json_writer *writer, Json_writer *writer,
bool is_analyze, bool is_analyze)
Filesort_tracker *fs_tracker,
bool first_table_sort_used)
{ {
Json_writer_nesting_guard guard(writer); Json_writer_nesting_guard guard(writer);
if (first_table_sort_used) if (using_filesort)
{ {
/* filesort was invoked on this join tab before doing the join with the rest */ /* filesort was invoked on this join tab before doing the join with the rest */
writer->add_member("read_sorted_file").start_object(); writer->add_member("read_sorted_file").start_object();
@@ -1526,6 +1443,7 @@ void Explain_table_access::print_explain_json(Explain_query *query,
} }
} }
writer->add_member("filesort").start_object(); writer->add_member("filesort").start_object();
if (is_analyze) if (is_analyze)
fs_tracker->print_json_members(writer); fs_tracker->print_json_members(writer);
} }
@@ -1718,7 +1636,7 @@ void Explain_table_access::print_explain_json(Explain_query *query,
writer->end_object(); writer->end_object();
} }
if (first_table_sort_used) if (using_filesort)
{ {
writer->end_object(); // filesort writer->end_object(); // filesort
writer->end_object(); // read_sorted_file writer->end_object(); // read_sorted_file

View File

@@ -176,9 +176,7 @@ public:
bool is_analyze); bool is_analyze);
void print_explain_json_interns(Explain_query *query, Json_writer *writer, void print_explain_json_interns(Explain_query *query, Json_writer *writer,
bool is_analyze, bool is_analyze);
Filesort_tracker *first_table_sort,
bool first_table_sort_used);
/* A flat array of Explain structs for tables. */ /* A flat array of Explain structs for tables. */
Explain_table_access** join_tabs; Explain_table_access** join_tabs;
@@ -186,6 +184,7 @@ public:
}; };
class Explain_aggr_node;
/* /*
EXPLAIN structure for a SELECT. EXPLAIN structure for a SELECT.
@@ -212,17 +211,9 @@ public:
having(NULL), having_value(Item::COND_UNDEF), having(NULL), having_value(Item::COND_UNDEF),
using_temporary(false), using_filesort(false), using_temporary(false), using_filesort(false),
time_tracker(is_analyze), time_tracker(is_analyze),
ops_tracker(is_analyze) aggr_tree(NULL)
{} {}
#if 0
/*
This is used to save the results of "late" test_if_skip_sort_order() calls
that are made from JOIN::exec
*/
void replace_table(uint idx, Explain_table_access *new_tab);
#endif
public: public:
const char *select_type; const char *select_type;
@@ -246,7 +237,11 @@ public:
/* ANALYZE members */ /* ANALYZE members */
Time_and_counter_tracker time_tracker; Time_and_counter_tracker time_tracker;
Sort_and_group_tracker ops_tracker; /*
Part of query plan describing sorting, temp.table usage, and duplicate
removal
*/
Explain_aggr_node* aggr_tree;
int print_explain(Explain_query *query, select_result_sink *output, int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze); uint8 explain_flags, bool is_analyze);
@@ -261,6 +256,48 @@ private:
Table_access_tracker using_temporary_read_tracker; Table_access_tracker using_temporary_read_tracker;
}; };
/////////////////////////////////////////////////////////////////////////////
// EXPLAIN structures for ORDER/GROUP operations.
/////////////////////////////////////////////////////////////////////////////
typedef enum
{
AGGR_OP_TEMP_TABLE,
AGGR_OP_FILESORT,
//AGGR_OP_READ_SORTED_FILE, // need this?
AGGR_OP_REMOVE_DUPLICATES
//AGGR_OP_JOIN // Need this?
} enum_explain_aggr_node_type;
class Explain_aggr_node : public Sql_alloc
{
public:
virtual enum_explain_aggr_node_type get_type()= 0;
virtual ~Explain_aggr_node() {}
Explain_aggr_node *child;
};
class Explain_aggr_filesort : public Explain_aggr_node
{
public:
enum_explain_aggr_node_type get_type() { return AGGR_OP_FILESORT; }
Filesort_tracker *tracker;
};
class Explain_aggr_tmp_table : public Explain_aggr_node
{
public:
enum_explain_aggr_node_type get_type() { return AGGR_OP_TEMP_TABLE; }
};
class Explain_aggr_remove_dups : public Explain_aggr_node
{
public:
enum_explain_aggr_node_type get_type() { return AGGR_OP_REMOVE_DUPLICATES; }
};
/////////////////////////////////////////////////////////////////////////////
/* /*
Explain structure for a UNION. Explain structure for a UNION.
@@ -618,7 +655,9 @@ public:
where_cond(NULL), where_cond(NULL),
cache_cond(NULL), cache_cond(NULL),
pushed_index_cond(NULL), pushed_index_cond(NULL),
sjm_nest(NULL) sjm_nest(NULL),
using_filesort(false),
fs_tracker(NULL)
{} {}
~Explain_table_access() { delete sjm_nest; } ~Explain_table_access() { delete sjm_nest; }
@@ -712,6 +751,8 @@ public:
Explain_basic_join *sjm_nest; Explain_basic_join *sjm_nest;
bool using_filesort;
Filesort_tracker *fs_tracker;
/* ANALYZE members */ /* ANALYZE members */
/* Tracker for reading the table */ /* Tracker for reading the table */
@@ -724,9 +765,7 @@ public:
uint select_id, const char *select_type, uint select_id, const char *select_type,
bool using_temporary, bool using_filesort); bool using_temporary, bool using_filesort);
void print_explain_json(Explain_query *query, Json_writer *writer, void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze, bool is_analyze);
Filesort_tracker *fs_tracker,
bool first_table_sort_used);
private: private:
void append_tag_name(String *str, enum explain_extra_tag tag); void append_tag_name(String *str, enum explain_extra_tag tag);

View File

@@ -3110,6 +3110,14 @@ void JOIN::save_explain_data(Explain_query *output, bool can_overwrite,
Explain_union *eu= output->get_union(nr); Explain_union *eu= output->get_union(nr);
explain= &eu->fake_select_lex_explain; explain= &eu->fake_select_lex_explain;
join_tab[0].tracker= eu->get_fake_select_lex_tracker(); join_tab[0].tracker= eu->get_fake_select_lex_tracker();
for (int i=0 ; i < top_join_tab_count + aggr_tables; i++)
{
if (join_tab[i].filesort)
{
join_tab[i].filesort->tracker=
new Filesort_tracker(thd->lex->analyze_stmt);
}
}
} }
} }
@@ -3123,7 +3131,6 @@ void JOIN::exec()
dbug_serve_apcs(thd, 1); dbug_serve_apcs(thd, 1);
); );
ANALYZE_START_TRACKING(&explain->time_tracker); ANALYZE_START_TRACKING(&explain->time_tracker);
explain->ops_tracker.report_join_start();
exec_inner(); exec_inner();
ANALYZE_STOP_TRACKING(&explain->time_tracker); ANALYZE_STOP_TRACKING(&explain->time_tracker);
@@ -17773,12 +17780,8 @@ do_select(JOIN *join, Procedure *procedure)
join->select_lex->select_number)) join->select_lex->select_number))
dbug_serve_apcs(join->thd, 1); dbug_serve_apcs(join->thd, 1);
); );
JOIN_TAB *join_tab=join->join_tab +join->top_join_tab_count;
for (uint i= 0; i < join->aggr_tables; i++, join_tab++) JOIN_TAB *join_tab= join->join_tab + join->const_tables;
{
join->explain->ops_tracker.report_tmp_table(join_tab->table);
}
join_tab= join->join_tab + join->const_tables;
if (join->outer_ref_cond && !join->outer_ref_cond->val_int()) if (join->outer_ref_cond && !join->outer_ref_cond->val_int())
error= NESTED_LOOP_NO_MORE_ROWS; error= NESTED_LOOP_NO_MORE_ROWS;
else else
@@ -21260,7 +21263,7 @@ create_sort_index(THD *thd, JOIN *join, JOIN_TAB *tab, Filesort *fsort)
table->file->info(HA_STATUS_VARIABLE); // Get record count table->file->info(HA_STATUS_VARIABLE); // Get record count
filesort_retval= filesort(thd, table, fsort, tab->keep_current_rowid, filesort_retval= filesort(thd, table, fsort, tab->keep_current_rowid,
&examined_rows, &found_rows, &examined_rows, &found_rows,
join->explain->ops_tracker.report_sorting(thd)); fsort->tracker);
table->sort.found_records= filesort_retval; table->sort.found_records= filesort_retval;
tab->records= found_rows; // For SQL_CALC_ROWS tab->records= found_rows; // For SQL_CALC_ROWS
@@ -21359,7 +21362,7 @@ JOIN_TAB::remove_duplicates()
DBUG_ASSERT(join->aggr_tables > 0 && table->s->tmp_table != NO_TMP_TABLE); DBUG_ASSERT(join->aggr_tables > 0 && table->s->tmp_table != NO_TMP_TABLE);
THD_STAGE_INFO(join->thd, stage_removing_duplicates); THD_STAGE_INFO(join->thd, stage_removing_duplicates);
join->explain->ops_tracker.report_duplicate_removal(); //join->explain->ops_tracker.report_duplicate_removal();
table->reginfo.lock_type=TL_WRITE; table->reginfo.lock_type=TL_WRITE;
@@ -23701,7 +23704,7 @@ int append_possible_keys(MEM_ROOT *alloc, String_list &list, TABLE *table,
void JOIN_TAB::save_explain_data(Explain_table_access *eta, void JOIN_TAB::save_explain_data(Explain_table_access *eta,
table_map prefix_tables, table_map prefix_tables,
bool distinct, JOIN_TAB *first_top_tab) bool distinct_arg, JOIN_TAB *first_top_tab)
{ {
int quick_type; int quick_type;
CHARSET_INFO *cs= system_charset_info; CHARSET_INFO *cs= system_charset_info;
@@ -23717,6 +23720,8 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta,
explain_plan= eta; explain_plan= eta;
eta->key.clear(); eta->key.clear();
eta->quick_info= NULL; eta->quick_info= NULL;
eta->using_filesort= false;
SQL_SELECT *tab_select; SQL_SELECT *tab_select;
/* /*
We assume that if this table does pre-sorting, then it doesn't do filtering We assume that if this table does pre-sorting, then it doesn't do filtering
@@ -23725,6 +23730,13 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta,
DBUG_ASSERT(!(select && filesort)); DBUG_ASSERT(!(select && filesort));
tab_select= (filesort)? filesort->select : select; tab_select= (filesort)? filesort->select : select;
if (filesort)
{
eta->using_filesort= true; // This fixes EXPLAIN
eta->fs_tracker= filesort->tracker=
new Filesort_tracker(thd->lex->analyze_stmt);
}
tracker= &eta->tracker; tracker= &eta->tracker;
jbuf_tracker= &eta->jbuf_tracker; jbuf_tracker= &eta->jbuf_tracker;
@@ -24128,6 +24140,46 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta,
} }
/*
Walk through join->aggr_tables and save aggregation/grouping query plan into
an Explain_select object
*/
void save_agg_explain_data(JOIN *join, Explain_select *xpl_sel)
{
JOIN_TAB *join_tab=join->join_tab + join->top_join_tab_count;
Explain_aggr_node *prev_node;
Explain_aggr_node *node= xpl_sel->aggr_tree;
for (uint i= 0; i < join->aggr_tables; i++, join_tab++)
{
// Each aggregate means a temp.table
prev_node= node;
node= new Explain_aggr_tmp_table;
node->child= prev_node;
if (join_tab->distinct)
{
prev_node= node;
node= new Explain_aggr_remove_dups;
node->child= prev_node;
}
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;
prev_node= node;
node= eaf;
node->child= prev_node;
}
}
xpl_sel->aggr_tree= node;
}
/* /*
Save Query Plan Footprint Save Query Plan Footprint
@@ -24135,8 +24187,9 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta,
Currently, this function may be called multiple times Currently, this function may be called multiple times
*/ */
int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table, int JOIN::save_explain_data_intern(Explain_query *output,
bool need_order, bool distinct, bool need_tmp_table_arg,
bool need_order_arg, bool distinct_arg,
const char *message) const char *message)
{ {
JOIN *join= this; /* Legacy: this code used to be a non-member function */ JOIN *join= this; /* Legacy: this code used to be a non-member function */
@@ -24166,7 +24219,7 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
explain->select_id= join->select_lex->select_number; explain->select_id= join->select_lex->select_number;
explain->select_type= join->select_lex->type; explain->select_type= join->select_lex->type;
explain->using_temporary= need_tmp; explain->using_temporary= need_tmp;
explain->using_filesort= need_order; explain->using_filesort= need_order_arg;
/* Setting explain->message means that all other members are invalid */ /* Setting explain->message means that all other members are invalid */
explain->message= message; explain->message= message;
@@ -24183,7 +24236,7 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
explain->select_id= select_lex->select_number; explain->select_id= select_lex->select_number;
explain->select_type= select_lex->type; explain->select_type= select_lex->type;
explain->using_temporary= need_tmp; explain->using_temporary= need_tmp;
explain->using_filesort= need_order; explain->using_filesort= need_order_arg;
explain->message= "Storage engine handles GROUP BY"; explain->message= "Storage engine handles GROUP BY";
if (select_lex->master_unit()->derived) if (select_lex->master_unit()->derived)
@@ -24204,42 +24257,7 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
if (select_lex->master_unit()->derived) if (select_lex->master_unit()->derived)
xpl_sel->connection_type= Explain_node::EXPLAIN_NODE_DERIVED; xpl_sel->connection_type= Explain_node::EXPLAIN_NODE_DERIVED;
if (need_tmp_table) save_agg_explain_data(this, xpl_sel);
xpl_sel->using_temporary= true;
if (need_order)
xpl_sel->using_filesort= true;
/*
Check whether we should display "Using filesort" or "Using temporary".
This is a temporary code, we need to save the 'true' plan structure for
EXPLAIN FORMAT=JSON.
*/
{
bool using_filesort_= false;
bool using_temporary_ = false;
/* The first non-const join table may do sorting */
JOIN_TAB *tab= first_top_level_tab(this, WITHOUT_CONST_TABLES);
if (tab)
{
if (tab->filesort)
using_filesort_= true;
if (tab->aggr)
using_temporary_= true;
}
/* Aggregation tabs are located at the end of top-level join tab array. */
JOIN_TAB *curr_tab= join_tab + top_join_tab_count;
for (uint i= 0; i < aggr_tables; i++, curr_tab++)
{
if (curr_tab->filesort)
using_filesort_= true;
if (curr_tab->aggr)
using_temporary_= true;
}
xpl_sel->using_temporary= using_temporary_;
xpl_sel->using_filesort= using_filesort_;
}
xpl_sel->exec_const_cond= exec_const_cond; xpl_sel->exec_const_cond= exec_const_cond;
if (tmp_having) if (tmp_having)
@@ -24297,7 +24315,7 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
prev_bush_root_tab= tab->bush_root_tab; prev_bush_root_tab= tab->bush_root_tab;
cur_parent->add_table(eta, output); cur_parent->add_table(eta, output);
tab->save_explain_data(eta, used_tables, distinct, first_top_tab); tab->save_explain_data(eta, used_tables, distinct_arg, first_top_tab);
if (saved_join_tab) if (saved_join_tab)
tab= saved_join_tab; tab= saved_join_tab;

View File

@@ -1484,6 +1484,7 @@ bool Window_func_runner::setup(THD *thd)
spec->partition_list->first, spec->partition_list->first,
spec->order_list->first); spec->order_list->first);
filesort= new (thd->mem_root) Filesort(sort_order, HA_POS_ERROR, NULL); filesort= new (thd->mem_root) Filesort(sort_order, HA_POS_ERROR, NULL);
filesort->tracker= new Filesort_tracker(thd->lex->analyze_stmt);
win_func->setup_partition_border_check(thd); win_func->setup_partition_border_check(thd);