Commit 44fdb56c authored by Sergei Petrunia's avatar Sergei Petrunia

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
parent 24cd633f
...@@ -685,13 +685,13 @@ ANALYZE ...@@ -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",
"filesort": { "temporary_table": {
"r_loops": 1, "filesort": {
"volatile parameter": "REPLACED", "r_loops": 1,
"r_used_priority_queue": false, "volatile parameter": "REPLACED",
"r_output_rows": 0, "r_used_priority_queue": false,
"volatile parameter": "REPLACED", "r_output_rows": 0,
"temporary_table": { "volatile parameter": "REPLACED",
"temporary_table": { "temporary_table": {
"table": { "table": {
"table_name": "t2", "table_name": "t2",
......
...@@ -173,7 +173,6 @@ EXPLAIN ...@@ -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 ...@@ -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,
"filesort": { "temporary_table": {
"r_loops": 1, "filesort": {
"r_total_time_ms": "REPLACED", "r_loops": 1,
"r_used_priority_queue": false, "r_total_time_ms": "REPLACED",
"r_output_rows": 6, "r_used_priority_queue": false,
"r_buffer_size": "REPLACED", "r_output_rows": 6,
"temporary_table": { "r_buffer_size": "REPLACED",
"temporary_table": { "temporary_table": {
"table": { "table": {
"table_name": "t6", "table_name": "t6",
...@@ -512,25 +511,28 @@ EXPLAIN ...@@ -512,25 +511,28 @@ EXPLAIN
"select_id": 1, "select_id": 1,
"filesort": { "filesort": {
"temporary_table": { "temporary_table": {
"function": "buffer", "filesort": {
"table": { "temporary_table": {
"table_name": "t6", "table": {
"access_type": "ALL", "table_name": "t6",
"rows": 5, "access_type": "ALL",
"filtered": 100, "rows": 5,
"attached_condition": "((t6.b > 0) and (t6.a <= 5))" "filtered": 100,
}, "attached_condition": "((t6.b > 0) and (t6.a <= 5))"
"block-nl-join": { },
"table": { "block-nl-join": {
"table_name": "t5", "table": {
"access_type": "ALL", "table_name": "t5",
"rows": 7, "access_type": "ALL",
"filtered": 100 "rows": 7,
}, "filtered": 100
"buffer_type": "flat", },
"buffer_size": "256Kb", "buffer_type": "flat",
"join_type": "BNL", "buffer_size": "256Kb",
"attached_condition": "(t5.a = t6.a)" "join_type": "BNL",
"attached_condition": "(t5.a = t6.a)"
}
}
} }
} }
} }
......
...@@ -231,8 +231,8 @@ CREATE VIEW v1 AS SELECT a, MIN(b) AS b FROM t2 GROUP BY a; ...@@ -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
......
...@@ -487,7 +487,6 @@ EXPLAIN ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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",
......
...@@ -5412,9 +5412,9 @@ WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND ...@@ -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
......
...@@ -1289,8 +1289,8 @@ SELECT t1.a, COUNT( t2.b ), SUM( t2.b ), MAX( t2.b ) ...@@ -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 ...@@ -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 ...@@ -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;
......
...@@ -1300,8 +1300,8 @@ SELECT t1.a, COUNT( t2.b ), SUM( t2.b ), MAX( t2.b ) ...@@ -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 ...@@ -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 ...@@ -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;
......
...@@ -7,8 +7,8 @@ explain select 1 from ...@@ -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)
......
...@@ -2003,8 +2003,8 @@ FROM t2 JOIN t3 ON t3.f4 = t2.f4 ...@@ -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 "
......
...@@ -50,6 +50,8 @@ class Filesort: public Sql_alloc ...@@ -50,6 +50,8 @@ class Filesort: public Sql_alloc
/** 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),
......
...@@ -69,75 +69,3 @@ void Filesort_tracker::print_json_members(Json_writer *writer) ...@@ -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++;
}
...@@ -284,174 +284,3 @@ class Filesort_tracker : public Sql_alloc ...@@ -284,174 +284,3 @@ class Filesort_tracker : public Sql_alloc
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; }
};
};
...@@ -697,14 +697,6 @@ bool Explain_node::print_explain_json_cache(Json_writer *writer, ...@@ -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, ...@@ -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, ...@@ -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;
Explain_aggr_node *node= aggr_tree;
if (is_analyze) for (; node; node= node->child)
{
/* 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)
{
if (action == EXPL_ACTION_FILESORT)
{
if (iter.is_last_element())
{
first_table_sort= fs_tracker;
break;
}
writer->add_member("filesort").start_object();
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();
started_objects++;
}
else
DBUG_ASSERT(0);
}
}
if (first_table_sort)
first_table_sort_used= true;
}
else
{ {
/* This is just EXPLAIN. Try to produce something meaningful */ switch (node->get_type())
if (using_temporary)
{ {
started_objects= 1; case AGGR_OP_TEMP_TABLE:
if (using_filesort) writer->add_member("temporary_table").start_object();
break;
case AGGR_OP_FILESORT:
{ {
started_objects++;
writer->add_member("filesort").start_object(); writer->add_member("filesort").start_object();
if (is_analyze)
((Explain_aggr_filesort*)node)->tracker->print_json_members(writer);
break;
} }
writer->add_member("temporary_table").start_object(); case AGGR_OP_REMOVE_DUPLICATES:
writer->add_member("function").add_str("buffer"); writer->add_member("duplicate_removal").start_object();
} break;
else default:
{ DBUG_ASSERT(0);
if (using_filesort)
first_table_sort_used= true;
} }
started_objects++;
} }
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, ...@@ -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, ...@@ -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, ...@@ -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 ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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
......
...@@ -176,9 +176,7 @@ class Explain_basic_join : public Explain_node ...@@ -176,9 +176,7 @@ class Explain_basic_join : public Explain_node
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 @@ class Explain_basic_join : public Explain_node ...@@ -186,6 +184,7 @@ class Explain_basic_join : public Explain_node
}; };
class Explain_aggr_node;
/* /*
EXPLAIN structure for a SELECT. EXPLAIN structure for a SELECT.
...@@ -212,17 +211,9 @@ class Explain_select : public Explain_basic_join ...@@ -212,17 +211,9 @@ class Explain_select : public Explain_basic_join
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;
...@@ -245,9 +236,13 @@ class Explain_select : public Explain_basic_join ...@@ -245,9 +236,13 @@ class Explain_select : public Explain_basic_join
/* 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);
void print_explain_json(Explain_query *query, Json_writer *writer, void print_explain_json(Explain_query *query, Json_writer *writer,
...@@ -261,6 +256,48 @@ class Explain_select : public Explain_basic_join ...@@ -261,6 +256,48 @@ class Explain_select : public Explain_basic_join
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 @@ class Explain_table_access : public Sql_alloc ...@@ -618,7 +655,9 @@ class Explain_table_access : public Sql_alloc
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; }
...@@ -711,7 +750,9 @@ class Explain_table_access : public Sql_alloc ...@@ -711,7 +750,9 @@ class Explain_table_access : public Sql_alloc
Item *pushed_index_cond; Item *pushed_index_cond;
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 @@ class Explain_table_access : public Sql_alloc ...@@ -724,9 +765,7 @@ class Explain_table_access : public Sql_alloc
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);
......
...@@ -3110,6 +3110,14 @@ void JOIN::save_explain_data(Explain_query *output, bool can_overwrite, ...@@ -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() ...@@ -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) ...@@ -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) ...@@ -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() ...@@ -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, ...@@ -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, ...@@ -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
...@@ -23724,6 +23729,13 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, ...@@ -23724,6 +23729,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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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)
...@@ -24203,43 +24256,8 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table, ...@@ -24203,43 +24256,8 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
xpl_sel->select_type= join->select_lex->type; xpl_sel->select_type= join->select_lex->type;
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, ...@@ -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;
......
...@@ -1484,6 +1484,7 @@ bool Window_func_runner::setup(THD *thd) ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment