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:
@@ -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",
|
||||||
|
@@ -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;
|
||||||
|
@@ -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
|
|||||||
"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",
|
||||||
|
@@ -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 )
|
|||||||
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;
|
||||||
|
@@ -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;
|
||||||
|
@@ -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
|
|||||||
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 @@ 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),
|
||||||
|
@@ -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 @@ 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; }
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
@@ -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);
|
||||||
|
@@ -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;
|
||||||
|
@@ -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);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user