Skip to content

Commit 93fc04f

Browse files
committed
MDEV-6995: EXPLAIN JSON and ORDER BY, GROUP BY, etc
- Make ANALYZE correctly remember and report filesort() calls - Temp.table use is collected but only basic info is reported.
1 parent f7002c0 commit 93fc04f

File tree

6 files changed

+339
-46
lines changed

6 files changed

+339
-46
lines changed

mysql-test/r/analyze_stmt_orderby.result

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,10 @@ ANALYZE
203203
"r_loops": 1,
204204
"r_total_time_ms": "REPLACED",
205205
"filesort": {
206+
"r_loops": 1,
207+
"r_limit": 4,
208+
"r_used_priority_queue": true,
209+
"r_output_rows": 4,
206210
"temporary_table": {
207211
"table": {
208212
"table_name": "t0",
@@ -318,4 +322,45 @@ ANALYZE
318322
}
319323
}
320324
drop table t2;
325+
create table t2 (
326+
a int,
327+
b int,
328+
c int
329+
);
330+
insert into t2
331+
select
332+
a.a+10*b.a+100*c.a,
333+
b.a+10*c.a,
334+
c.a
335+
from t0 a, t0 b, t0 c;
336+
analyze format=json
337+
select MAX(b) from t2 where mod(a,2)=0 group by c;
338+
ANALYZE
339+
{
340+
"query_block": {
341+
"select_id": 1,
342+
"r_loops": 1,
343+
"r_total_time_ms": "REPLACED",
344+
"filesort": {
345+
"r_loops": 1,
346+
"r_used_priority_queue": false,
347+
"r_output_rows": 10,
348+
"r_buffer_size": "REPLACED",
349+
"temporary_table": {
350+
"table": {
351+
"table_name": "t2",
352+
"access_type": "ALL",
353+
"r_loops": 1,
354+
"rows": 1000,
355+
"r_rows": 1000,
356+
"r_total_time_ms": "REPLACED",
357+
"filtered": 100,
358+
"r_filtered": 50,
359+
"attached_condition": "((t2.a % 2) = 0)"
360+
}
361+
}
362+
}
363+
}
364+
}
365+
drop table t2;
321366
drop table t0, t1;

mysql-test/t/analyze_stmt_orderby.test

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,5 +69,25 @@ select * from t0,t2 where t2.a=t0.a order by t0.a limit 4;
6969
analyze format=json
7070
select * from t0,t2 where t2.a=t0.a order by t0.a limit 4;
7171

72+
drop table t2;
73+
74+
75+
create table t2 (
76+
a int,
77+
b int,
78+
c int
79+
);
80+
insert into t2
81+
select
82+
a.a+10*b.a+100*c.a,
83+
b.a+10*c.a,
84+
c.a
85+
from t0 a, t0 b, t0 c;
86+
87+
--replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ /"r_buffer_size": "[^"]+"/"r_buffer_size": "REPLACED"/
88+
analyze format=json
89+
select MAX(b) from t2 where mod(a,2)=0 group by c;
90+
7291
drop table t2;
7392
drop table t0, t1;
93+

sql/sql_analyze_stmt.cc

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
#include "sql_select.h"
2424
#include "my_json_writer.h"
2525

26-
void Filesort_tracker::print_json(Json_writer *writer)
26+
void Filesort_tracker::print_json_members(Json_writer *writer)
2727
{
2828
const char *varied_str= "(varied across executions)";
2929
writer->add_member("r_loops").add_ll(r_loops);
@@ -60,3 +60,56 @@ void Filesort_tracker::print_json(Json_writer *writer)
6060
}
6161
}
6262

63+
64+
/*
65+
Report that we are doing a filesort.
66+
@return
67+
Tracker object to be used with filesort
68+
*/
69+
70+
Filesort_tracker *Sort_and_group_tracker::report_sorting()
71+
{
72+
DBUG_ASSERT(cur_action < MAX_QEP_ACTIONS);
73+
74+
if (total_actions)
75+
{
76+
/* This is not the first execution. Check */
77+
if (qep_actions[cur_action] != EXPL_ACTION_FILESORT)
78+
{
79+
varied_executions= true;
80+
cur_action++;
81+
if (!dummy_fsort_tracker)
82+
dummy_fsort_tracker= new (current_thd->mem_root) Filesort_tracker();
83+
return dummy_fsort_tracker;
84+
}
85+
return qep_actions_data[cur_action++].filesort_tracker;
86+
}
87+
88+
Filesort_tracker *fs_tracker= new(current_thd->mem_root)Filesort_tracker();
89+
qep_actions_data[cur_action].filesort_tracker= fs_tracker;
90+
qep_actions[cur_action++]= EXPL_ACTION_FILESORT;
91+
92+
return fs_tracker;
93+
}
94+
95+
96+
void Sort_and_group_tracker::report_tmp_table(TABLE *tbl)
97+
{
98+
DBUG_ASSERT(cur_action < MAX_QEP_ACTIONS);
99+
if (total_actions)
100+
{
101+
/* This is not the first execution. Check if the steps match. */
102+
// todo: should also check that tmp.table kinds are the same.
103+
if (qep_actions[cur_action] != EXPL_ACTION_TEMPTABLE)
104+
varied_executions= true;
105+
}
106+
107+
if (!varied_executions)
108+
{
109+
qep_actions[cur_action]= EXPL_ACTION_TEMPTABLE;
110+
// qep_actions_data[cur_action]= ....
111+
}
112+
113+
cur_action++;
114+
}
115+

sql/sql_analyze_stmt.h

Lines changed: 153 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ class Filesort_tracker : public Sql_alloc
214214
}
215215

216216
/* Functions to get the statistics */
217-
void print_json(Json_writer *writer);
217+
void print_json_members(Json_writer *writer);
218218

219219
ulonglong get_r_loops() { return r_loops; }
220220
double get_avg_examined_rows()
@@ -283,6 +283,7 @@ typedef enum
283283

284284
typedef enum
285285
{
286+
EXPL_ACTION_EOF, /* not-an-action */
286287
EXPL_ACTION_FILESORT,
287288
EXPL_ACTION_TEMPTABLE,
288289
EXPL_ACTION_REMOVE_DUPS,
@@ -329,12 +330,121 @@ typedef enum
329330
///TODO: handle repeated execution with subselects!
330331
*/
331332

333+
class Sort_and_group_tracker : public Sql_alloc
334+
{
335+
enum { MAX_QEP_ACTIONS = 5 };
336+
337+
/* Query actions in the order they were made. */
338+
enum_qep_action qep_actions[MAX_QEP_ACTIONS];
339+
340+
/* Number for the next action */
341+
int cur_action;
342+
343+
/*
344+
Non-zero means there was already an execution which had
345+
#total_actions actions
346+
*/
347+
int total_actions;
348+
349+
int get_n_actions()
350+
{
351+
return total_actions? total_actions: cur_action;
352+
}
353+
354+
/*
355+
TRUE<=>there were executions which took different sort/buffer/de-duplicate
356+
routes. The counter values are not meaningful.
357+
*/
358+
bool varied_executions;
359+
360+
/* Details about query actions */
361+
union
362+
{
363+
Filesort_tracker *filesort_tracker;
364+
enum_tmp_table_use tmp_table;
365+
}
366+
qep_actions_data[MAX_QEP_ACTIONS];
367+
368+
Filesort_tracker *dummy_fsort_tracker;
369+
370+
public:
371+
Sort_and_group_tracker() :
372+
cur_action(0), total_actions(0), varied_executions(false),
373+
dummy_fsort_tracker(NULL)
374+
{}
375+
376+
/*************** Reporting interface ***************/
377+
/* Report that join execution is started */
378+
void report_join_start()
379+
{
380+
if (!total_actions && cur_action != 0)
381+
{
382+
/* This is a second execution */
383+
total_actions= cur_action;
384+
}
385+
cur_action= 0;
386+
}
387+
388+
/*
389+
Report that a temporary table is created. The next step is to write to the
390+
this tmp. table
391+
*/
392+
void report_tmp_table(TABLE *tbl);
393+
394+
/*
395+
Report that we are doing a filesort.
396+
@return
397+
Tracker object to be used with filesort
398+
*/
399+
Filesort_tracker *report_sorting();
400+
401+
friend class Iterator;
402+
/*************** Statistics retrieval interface ***************/
403+
bool had_varied_executions() { return varied_executions; }
404+
405+
class Iterator
406+
{
407+
Sort_and_group_tracker *owner;
408+
int idx;
409+
public:
410+
Iterator(Sort_and_group_tracker *owner_arg) :
411+
owner(owner_arg), idx(owner_arg->get_n_actions() - 1)
412+
{}
413+
414+
enum_qep_action get_next(Filesort_tracker **tracker/*,
415+
enum_tmp_table_use *tmp_table_use*/)
416+
{
417+
/* Walk back through the array... */
418+
if (idx < 0)
419+
return EXPL_ACTION_EOF;
420+
switch (owner->qep_actions[idx])
421+
{
422+
case EXPL_ACTION_FILESORT:
423+
*tracker= owner->qep_actions_data[idx].filesort_tracker;
424+
break;
425+
case EXPL_ACTION_TEMPTABLE:
426+
//*tmp_table_use= tmp_table_kind[tmp_table_idx++];
427+
break;
428+
default:
429+
break;
430+
}
431+
return owner->qep_actions[idx--];
432+
}
433+
434+
bool is_last_element() { return idx == -1; }
435+
};
436+
};
437+
438+
#if 0
332439
class Sort_and_group_tracker : public Sql_alloc
333440
{
334441
enum { MAX_QEP_ACTIONS = 5 };
335442

336443
/* Query actions in the order they were made */
337444
enum_qep_action qep_actions[MAX_QEP_ACTIONS];
445+
446+
/* Index in filesort_tracker or tmp_table_kind arrays */
447+
int qep_action_idx[MAX_QEP_ACTIONS];
338448
uint n_actions;
339449

340450
/*
@@ -348,7 +458,7 @@ class Sort_and_group_tracker : public Sql_alloc
348458
enum_tmp_table_use tmp_table_kind[2];
349459
int cur_tmp_table;
350460

351-
friend class Explain_select;
461+
//friend class Explain_select;
352462

353463
public:
354464
Sort_and_group_tracker() :
@@ -366,7 +476,10 @@ class Sort_and_group_tracker : public Sql_alloc
366476
cur_tmp_table= 0;
367477
}
368478

369-
/* Report that a temporary table is created. */
479+
/*
480+
Report that a temporary table is created. The next step is to write to the
481+
this tmp. table
482+
*/
370483
void report_tmp_table(TABLE *tbl)
371484
{
372485
DBUG_ASSERT(n_actions < MAX_QEP_ACTIONS);
@@ -385,8 +498,44 @@ class Sort_and_group_tracker : public Sql_alloc
385498
DBUG_ASSERT(cur_tracker < 2);
386499
return &filesort_tracker[cur_tracker++];
387500
}
388-
501+
502+
friend class Iterator;
389503
/*************** Statistics retrieval interface ***************/
504+
// need to iterate over steps
505+
#if 0
506+
class Iterator
507+
{
508+
Sort_and_group_tracker *owner;
509+
uint idx;
510+
int fs_tracker_idx;
511+
//int tmp_table_idx;
512+
public:
513+
Iterator(Sort_and_group_tracker *owner_arg) :
514+
owner(owner_arg), idx(0), fs_tracker_idx(0)//, tmp_table_idx(0)
515+
{}
516+
517+
enum_qep_action get_next(Filesort_tracker **tracker/*,
518+
enum_tmp_table_use *tmp_table_use*/)
519+
{
520+
/* Walk back through the array... */
521+
if (idx >= owner->n_actions)
522+
return EXPL_ACTION_EOF;
523+
switch (owner->qep_actions[idx])
524+
{
525+
case EXPL_ACTION_FILESORT:
526+
*tracker= &owner->filesort_tracker[fs_tracker_idx++];
527+
break;
528+
case EXPL_ACTION_TEMPTABLE:
529+
//*tmp_table_use= tmp_table_kind[tmp_table_idx++];
530+
break;
531+
default:
532+
break;
533+
}
534+
return owner->qep_actions[idx++];
535+
}
536+
};
537+
#endif
390538
//enum_tmp_table_use get_tmp_table_type() { return join_result_tmp_table; }
391539
};
540+
#endif
392541

0 commit comments

Comments
 (0)