Quelle sql_explain.h
Sprache: C
/*
Copyright ( c ) 2013 Monty Program Ab
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; version 2 of the License .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
/*
= = EXPLAIN / ANALYZE architecture = =
= = = [ SHOW ] EXPLAIN data = = =
Query optimization produces two data structures :
1 . execution data structures themselves ( eg . JOINs , JOIN_TAB , etc , etc )
2 . Explain data structures .
# 2 are self contained set of data structures that has sufficient info to
produce output of SHOW EXPLAIN , EXPLAIN [ FORMAT = JSON ] , or
ANALYZE [ FORMAT = JSON ] , without accessing the execution data structures .
The exception is that Explain data structures have Item * pointers . See
ExplainDataStructureLifetime below for details .
= = = ANALYZE data = = =
EXPLAIN data structures have embedded ANALYZE data structures . These are
objects that are used to track how the parts of query plan were executed :
how many times each part of query plan was invoked , how many rows were
read / returned , etc .
Each execution data structure keeps a direct pointer to its ANALYZE data
structure . It is needed so that execution code can quickly increment the
counters .
( note that this increases the set of data that is frequently accessed
during the execution . What is the impact of this ? )
Since ANALYZE / EXPLAIN data structures are separated from execution data
structures , it is easy to have them survive until the end of the query ,
where we can return ANALYZE [ FORMAT = JSON ] output to the user , or print
it into the slow query log .
*/
#ifndef SQL_EXPLAIN_INCLUDED
#define SQL_EXPLAIN_INCLUDED
#include "opt_range.h"
class String_list: public List<char >
{
public :
const char *append_str(MEM_ROOT *mem_root, const char *str);
};
class Json_writer;
/**************************************************************************************
Data structures for producing EXPLAIN outputs .
These structures
- Can be produced inexpensively from query plan .
- Store sufficient information to produce tabular EXPLAIN output ( the goal is
to be able to produce JSON also )
*************************************************************************************/
class Explain_query;
/*
A node can be either a SELECT , or a UNION .
*/
class Explain_node : public Sql_alloc
{
public :
Explain_node(MEM_ROOT *root) :
cache_tracker(NULL),
subq_materialization(NULL),
connection_type(EXPLAIN_NODE_OTHER),
children(root)
{}
/* A type specifying what kind of node this is */
enum explain_node_type
{
EXPLAIN_UNION,
EXPLAIN_SELECT,
EXPLAIN_BASIC_JOIN,
EXPLAIN_UPDATE,
EXPLAIN_DELETE,
EXPLAIN_INSERT
};
/* How this node is connected */
enum explain_connection_type {
EXPLAIN_NODE_OTHER,
EXPLAIN_NODE_DERIVED, /* Materialized derived table */
EXPLAIN_NODE_NON_MERGED_SJ /* aka JTBM semi-join */
};
virtual enum explain_node_type get_type()= 0 ;
virtual uint get_select_id()= 0 ;
/**
expression cache statistics
*/
Expression_cache_tracker* cache_tracker;
/**
If not NULL , this node is a SELECT ( or UNION ) in a materialized
IN - subquery .
*/
Explain_subq_materialization* subq_materialization;
/*
How this node is connected to its parent .
( NOTE : EXPLAIN_NODE_NON_MERGED_SJ is set very late currently )
*/
enum explain_connection_type connection_type;
protected :
/*
A node may have children nodes . When a node ' s explain structure is
created , children nodes may not yet have QPFs . This is why we store ids .
*/
Dynamic_array<int > children;
public :
void add_child(int select_no)
{
children.append(select_no);
}
virtual int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze)=0 ;
virtual void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze)= 0 ;
int print_explain_for_children(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze);
void print_explain_json_for_children(Explain_query *query,
Json_writer *writer, bool is_analyze);
bool print_explain_json_cache(Json_writer *writer, bool is_analyze);
bool print_explain_json_subq_materialization(Json_writer *writer,
bool is_analyze);
virtual ~Explain_node() = default ;
};
class Explain_table_access;
/*
A basic join . This is only used for SJ - Materialization nests .
Basic join doesn ' t have ORDER / GROUP / DISTINCT operations . It also cannot be
degenerate .
It has its own select_id .
*/
class Explain_basic_join : public Explain_node
{
public :
enum explain_node_type get_type() override { return EXPLAIN_BASIC_JOIN; }
Explain_basic_join(MEM_ROOT *root) : Explain_node(root), join_tabs(NULL) {}
~Explain_basic_join();
bool add_table(Explain_table_access *tab, Explain_query *query);
uint get_select_id() override { return select_id; }
uint select_id;
int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze) override;
void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze) override;
void print_explain_json_interns(Explain_query *query, Json_writer *writer,
bool is_analyze);
/* A flat array of Explain structs for tables. */
Explain_table_access** join_tabs;
uint n_join_tabs;
};
class Explain_aggr_node;
/*
EXPLAIN structure for a SELECT .
A select can be :
1 . A degenerate case . In this case , message ! = NULL , and it contains a
description of what kind of degenerate case it is ( e . g . " Impossible
WHERE " ) .
2 . a non - degenerate join . In this case , join_tabs describes the join .
In the non - degenerate case , a SELECT may have a GROUP BY / ORDER BY operation .
In both cases , the select may have children nodes . class Explain_node
provides a way get node ' s children .
*/
class Explain_select : public Explain_basic_join
{
public :
enum explain_node_type get_type() override { return EXPLAIN_SELECT; }
Explain_select(MEM_ROOT *root, bool is_analyze) :
Explain_basic_join(root),
#ifndef DBUG_OFF
select_lex(NULL),
#endif
linkage(UNSPECIFIED_TYPE),
is_lateral(false ),
message(NULL),
having(NULL), having_value(Item::COND_UNDEF),
using_temporary(false ), using_filesort(false ),
cost(0 .0 ),
time_tracker(is_analyze),
aggr_tree(NULL)
{}
void add_linkage(Json_writer *writer);
public :
#ifndef DBUG_OFF
SELECT_LEX *select_lex;
#endif
const char *select_type;
enum sub_select_type linkage;
bool is_lateral;
/*
If message ! = NULL , this is a degenerate join plan , and all subsequent
members have no info
*/
const char *message;
/* Expensive constant condition */
Item *exec_const_cond;
Item *outer_ref_cond;
Item *pseudo_bits_cond;
/* HAVING condition */
Item *having;
Item::cond_result having_value;
/* Global join attributes. In tabular form, they are printed on the first row */
bool using_temporary;
bool using_filesort;
double cost;
/* ANALYZE members */
Time_and_counter_tracker time_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,
uint8 explain_flags, bool is_analyze) override;
void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze) override;
Table_access_tracker *get_using_temporary_read_tracker()
{
return &using_temporary_read_tracker;
}
private :
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_WINDOW_FUNCS
//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() = default ;
Explain_aggr_node *child;
};
class Explain_aggr_filesort : public Explain_aggr_node
{
List<Item> sort_items;
List<ORDER::enum_order> sort_directions;
public :
enum_explain_aggr_node_type get_type() override { return AGGR_OP_FILESORT; }
Filesort_tracker tracker;
Explain_aggr_filesort(MEM_ROOT *mem_root, bool is_analyze,
Filesort *filesort);
void print_json_members(Json_writer *writer, bool is_analyze);
};
class Explain_aggr_tmp_table : public Explain_aggr_node
{
public :
enum_explain_aggr_node_type get_type() override { return AGGR_OP_TEMP_TABLE; }
};
class Explain_aggr_remove_dups : public Explain_aggr_node
{
public :
enum_explain_aggr_node_type get_type() override { return AGGR_OP_REMOVE_DUPLICATES; }
};
class Explain_aggr_window_funcs : public Explain_aggr_node
{
List<Explain_aggr_filesort> sorts;
public :
enum_explain_aggr_node_type get_type() override { return AGGR_OP_WINDOW_FUNCS; }
void print_json_members(Json_writer *writer, bool is_analyze);
friend class Window_funcs_computation;
};
/////////////////////////////////////////////////////////////////////////////
extern const char *unit_operation_text[4 ];
extern const char *pushed_unit_operation_text[4 ];
extern const char *pushed_derived_text;
extern const char *pushed_select_text;
/*
Explain structure for a UNION [ ALL ] .
A UNION may or may not have " Using filesort " .
*/
class Explain_union : public Explain_node
{
public :
Explain_union(MEM_ROOT *root, bool is_analyze) :
Explain_node(root), union_members(PSI_INSTRUMENT_MEM),
is_recursive_cte(false ), is_pushed_down_to_engine(false ),
fake_select_lex_explain(root, is_analyze)
{}
enum explain_node_type get_type() override { return EXPLAIN_UNION; }
unit_common_op operation;
uint get_select_id() override
{
DBUG_ASSERT(union_members.elements() > 0 );
return union_members.at(0 );
}
/*
Members of the UNION . Note : these are different from UNION ' s " children " .
Example :
( select * from t1 ) union
( select * from t2 ) order by ( select col1 from t3 . . . )
here
- select - from - t1 and select - from - t2 are " union members " ,
- select - from - t3 is the only " child " .
*/
Dynamic_array<int > union_members;
void add_select(int select_no)
{
union_members.append(select_no);
}
int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze) override;
void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze) override;
void print_explain_json_regular(Explain_query *query, Json_writer *writer,
bool is_analyze);
void print_explain_json_pushed_down(Explain_query *query,
Json_writer *writer, bool is_analyze);
const char *fake_select_type;
bool using_filesort;
bool using_tmp;
bool is_recursive_cte;
bool is_pushed_down_to_engine;
/*
Explain data structure for " fake_select_lex " ( i . e . for the degenerate
SELECT that reads UNION result ) .
It doesn ' t have a query plan , but we still need execution tracker , etc .
*/
Explain_select fake_select_lex_explain;
Table_access_tracker *get_fake_select_lex_tracker()
{
return &fake_select_lex_tracker;
}
Table_access_tracker *get_tmptable_read_tracker()
{
return &tmptable_read_tracker;
}
private :
uint make_union_table_name(char *buf);
int print_explain_regular(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze);
int print_explain_pushed_down(select_result_sink *output,
uint8 explain_flags, bool is_analyze);
Table_access_tracker fake_select_lex_tracker;
/* This one is for reading after ORDER BY */
Table_access_tracker tmptable_read_tracker;
};
class Explain_update;
class Explain_delete;
class Explain_insert;
/*
Explain structure for a query ( i . e . a statement ) .
This should be able to survive when the query plan was deleted . Currently ,
we do not intend for it survive until after query ' s MEM_ROOT is freed .
= = ExplainDataStructureLifetime = =
> dispatch_command
| > mysql_parse
| | . . .
| |
| | explain - > query_plan_ready ( ) ; // (1)
| |
| | some_join - > cleanup ( ) ; // (2)
| |
| | explain - > notify_tables_are_closed ( ) ; // (3)
| | close_thread_tables ( ) ; // (4)
| | . . .
| | free_items ( ) ; // (5)
| | . . .
| |
| < mysql_parse
|
| log_slow_statement ( ) // (6)
|
| free_root ( )
|
> dispatch_command
( 1 ) - Query plan construction is finished and it is available for reading .
( 2 ) - Temporary tables are freed ( with exception of derived tables
which are freed at step ( 4 ) ) .
The tables are no longer accessible but one can still call
item - > print ( ) , even for items that refer to temp . tables ( see
Item_field : : print ( ) for details )
( 3 ) - Notification about ( 4 ) .
( 4 ) - Tables used by the query are closed . One consequence of this is that
the values of the const tables ' fields are not available anymore .
We could adjust the code in Item_field : : print ( ) to handle this but
instead we make step ( 3 ) disallow production of FORMAT = JSON output .
We also disable processing of SHOW EXPLAIN | ANALYZE output because
the query is about to finish anyway .
( 5 ) - Item objects are freed . After this , it ' s certainly not possible to
print them into FORMAT = JSON output .
( 6 ) - We may decide to log tabular EXPLAIN output to the slow query log .
*/
class Explain_query : public Sql_alloc
{
public :
Explain_query(THD *thd, MEM_ROOT *root);
~Explain_query();
/* Add a new node */
void add_node(Explain_node *node);
void add_insert_plan(Explain_insert *insert_plan_arg);
void add_upd_del_plan(Explain_update *upd_del_plan_arg);
/* This will return a select, or a union */
Explain_node *get_node(uint select_id);
/* This will return a select (even if there is a union with this id) */
Explain_select *get_select(uint select_id);
Explain_union *get_union(uint select_id);
/* Produce a tabular EXPLAIN output */
int print_explain(select_result_sink *output, uint8 explain_flags,
bool is_analyze);
/* Send tabular EXPLAIN to the client */
int send_explain(THD *thd, bool extended);
/* Return tabular EXPLAIN output as a text string */
bool print_explain_str(THD *thd, String *out_str, bool is_analyze);
int print_explain_json(select_result_sink *output, bool is_analyze,
ulonglong query_time_in_progress_ms= 0 );
/* If true, at least part of EXPLAIN can be printed */
bool have_query_plan() { return insert_plan || upd_del_plan|| get_node(1 ) != NULL; }
void query_plan_ready();
void notify_tables_are_closed();
bool is_query_plan_ready();
MEM_ROOT *mem_root;
Explain_update *get_upd_del_plan() { return upd_del_plan; }
private :
bool print_query_blocks_json(Json_writer *writer, const bool is_analyze);
void print_query_optimization_json(Json_writer *writer);
void send_explain_json_to_output(Json_writer *writer, select_result_sink *output);
/* Explain_delete inherits from Explain_update */
Explain_update *upd_del_plan;
/* Query "plan" for INSERTs */
Explain_insert *insert_plan;
Dynamic_array<Explain_union*> unions;
Dynamic_array<Explain_select*> selects;
THD *stmt_thd; // for APC start/stop
bool apc_enabled;
/*
Debugging aid : count how many times add_node ( ) was called . Ideally , it
should be one , we currently allow O ( 1 ) query plan saves for each
select or union . The goal is not to have O ( # rows_in_some_table ) , which
is unacceptable .
*/
longlong operations;
#ifndef DBUG_OFF
bool can_print_json= false ;
#endif
Exec_time_tracker optimization_time_tracker;
};
/*
Some of the tags have matching text . See extra_tag_text for text names , and
Explain_table_access : : append_tag_name ( ) for code to convert from tag form to text
form .
*/
enum explain_extra_tag
{
ET_none= 0 , /* not-a-tag */
ET_USING_INDEX_CONDITION,
ET_USING_INDEX_CONDITION_BKA,
ET_USING, /* For quick selects of various kinds */
ET_RANGE_CHECKED_FOR_EACH_RECORD,
ET_USING_WHERE_WITH_PUSHED_CONDITION,
ET_USING_WHERE,
ET_NOT_EXISTS,
ET_USING_INDEX,
ET_FULL_SCAN_ON_NULL_KEY,
ET_SKIP_OPEN_TABLE,
ET_OPEN_FRM_ONLY,
ET_OPEN_FULL_TABLE,
ET_SCANNED_0_DATABASES,
ET_SCANNED_1_DATABASE,
ET_SCANNED_ALL_DATABASES,
ET_USING_INDEX_FOR_GROUP_BY,
ET_USING_MRR, // does not print "Using mrr".
ET_DISTINCT,
ET_LOOSESCAN,
ET_START_TEMPORARY,
ET_END_TEMPORARY,
ET_FIRST_MATCH,
ET_USING_JOIN_BUFFER,
ET_CONST_ROW_NOT_FOUND,
ET_UNIQUE_ROW_NOT_FOUND,
ET_IMPOSSIBLE_ON_CONDITION,
ET_TABLE_FUNCTION,
ET_total
};
/*
Explain data structure describing join buffering use .
*/
class EXPLAIN_BKA_TYPE
{
public :
EXPLAIN_BKA_TYPE() : join_alg(NULL), is_bka(false ) {}
size_t join_buffer_size;
bool incremental;
/*
NULL if no join buffering used .
Other values : BNL , BNLH , BKA , BKAH .
*/
const char *join_alg;
/* true <=> BKA is used */
bool is_bka;
/* Information about MRR usage. */
StringBuffer<64 > mrr_type;
bool is_using_jbuf() { return (join_alg != NULL); }
};
/*
Data about how an index is used by some access method
*/
class Explain_index_use : public Sql_alloc
{
char *key_name;
uint key_len;
char *filter_name;
uint filter_len;
public :
String_list key_parts_list;
Explain_index_use()
{
clear();
}
void clear()
{
key_name= NULL;
key_len= (uint)-1 ;
filter_name= NULL;
filter_len= (uint)-1 ;
}
bool set(MEM_ROOT *root, KEY *key_name, uint key_len_arg);
bool set_pseudo_key(MEM_ROOT *root, const char *key_name);
inline const char *get_key_name() const { return key_name; }
inline uint get_key_len() const { return key_len; }
//inline const char *get_filter_name() const { return filter_name; }
};
/*
Query Plan data structure for Rowid filter .
*/
class Explain_rowid_filter : public Sql_alloc
{
public :
/* Quick select used to collect the rowids into filter */
Explain_quick_select *quick;
/* How many rows the above quick select is expected to return */
ha_rows rows;
/* Expected selectivity for the filter */
double selectivity;
/* Tracker with the information about how rowid filter is executed */
Rowid_filter_tracker *tracker;
void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze);
};
/*
QPF for quick range selects , as well as index_merge select
*/
class Explain_quick_select : public Sql_alloc
{
public :
Explain_quick_select(int quick_type_arg) : quick_type(quick_type_arg)
{}
const int quick_type;
bool is_basic()
{
return (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE ||
quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC ||
quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX);
}
/* This is used when quick_type == QUICK_SELECT_I::QS_TYPE_RANGE */
Explain_index_use range;
/* Used in all other cases */
List<Explain_quick_select> children;
void print_extra(String *str);
void print_key(String *str);
void print_key_len(String *str);
void print_json(Json_writer *writer);
void print_extra_recursive(String *str);
private :
const char *get_name_by_type();
};
/*
Data structure for " range checked for each record " .
It ' s a set of keys , tabular explain prints hex bitmap , json prints key names .
*/
typedef const char * NAME;
class Explain_range_checked_fer : public Sql_alloc
{
public :
String_list key_set;
key_map keys_map;
private :
ha_rows full_scan, index_merge;
ha_rows *keys_stat;
NAME *keys_stat_names;
uint keys;
public :
Explain_range_checked_fer()
:Sql_alloc(), full_scan(0 ), index_merge(0 ),
keys_stat(0 ), keys_stat_names(0 ), keys(0 )
{}
int append_possible_keys_stat(MEM_ROOT *alloc,
TABLE *table, key_map possible_keys);
void collect_data(QUICK_SELECT_I *quick);
void print_json(Json_writer *writer, bool is_analyze);
};
/*
EXPLAIN data structure for a single JOIN_TAB .
*/
class Explain_table_access : public Sql_alloc
{
public :
Explain_table_access(MEM_ROOT *root, bool timed) :
derived_select_number(0 ),
non_merged_sjm_number(0 ),
cost(0 .0 ),
loops(0 .0 ),
extra_tags(root),
range_checked_fer(NULL),
full_scan_on_null_key(false ),
start_dups_weedout(false ),
end_dups_weedout(false ),
where_cond(NULL),
cache_cond(NULL),
pushed_index_cond(NULL),
sjm_nest(NULL),
pre_join_sort(NULL),
handler_for_stats(NULL),
jbuf_unpack_tracker(timed),
rowid_filter(NULL)
{}
~Explain_table_access() { delete sjm_nest; }
void push_extra(enum explain_extra_tag extra_tag);
/* Internals */
/* id and 'select_type' are cared-of by the parent Explain_select */
StringBuffer<32 > table_name{system_charset_info};
StringBuffer<32 > used_partitions{system_charset_info};
String_list used_partitions_list;
// valid with ET_USING_MRR
StringBuffer<32 > mrr_type;
StringBuffer<32 > firstmatch_table_name{system_charset_info};
/*
Non - zero number means this is a derived table . The number can be used to
find the query plan for the derived table
*/
int derived_select_number;
/* TODO: join with the previous member. */
int non_merged_sjm_number;
enum join_type type;
bool used_partitions_set;
/* Empty means "NULL" will be printed */
String_list possible_keys;
bool rows_set; /* not set means 'NULL' should be printed */
bool filtered_set; /* not set means 'NULL' should be printed */
// Valid if ET_USING_INDEX_FOR_GROUP_BY is present
bool loose_scan_is_scanning;
/*
Index use : key name and length .
Note : that when one is accessing I_S tables , those may show use of
non - existant indexes .
key . key_name = = NULL means ' NULL ' will be shown in tabular output .
key . key_len = = ( uint ) - 1 means ' NULL ' will be shown in tabular output .
*/
Explain_index_use key;
/*
when type = = JT_HASH_NEXT , ' key ' stores the hash join pseudo - key .
hash_next_key stores the table ' s key .
*/
Explain_index_use hash_next_key;
String_list ref_list;
ha_rows rows;
double filtered;
/* Total cost incurred during one execution of this select */
double cost;
double loops;
/*
Contents of the ' Extra ' column . Some are converted into strings , some have
parameters , values for which are stored below .
*/
Dynamic_array<enum explain_extra_tag> extra_tags;
// Valid if ET_USING tag is present
Explain_quick_select *quick_info;
/* Non-NULL value means this tab uses "range checked for each record" */
Explain_range_checked_fer *range_checked_fer;
bool full_scan_on_null_key;
// valid with ET_USING_JOIN_BUFFER
EXPLAIN_BKA_TYPE bka_type;
bool start_dups_weedout;
bool end_dups_weedout;
/*
Note : lifespan of WHERE condition is less than lifespan of this object .
The below two are valid if tags include " ET_USING_WHERE " .
( TODO : indexsubquery may put ET_USING_WHERE without setting where_cond ? )
*/
Item *where_cond;
Item *cache_cond;
/*
This is either pushed index condition , or BKA ' s index condition .
( the latter refers to columns of other tables and so can only be checked by
BKA code ) . Examine extra_tags ( or bka_type . is_bka ) to tell which one it is .
*/
Item *pushed_index_cond;
Explain_basic_join *sjm_nest;
/*
This describes a possible filesort ( ) call that is done before doing the
join operation .
*/
Explain_aggr_filesort *pre_join_sort;
/* ANALYZE members */
/* Tracker for reading the table */
Table_access_tracker tracker;
Exec_time_tracker op_tracker;
Gap_time_tracker extra_time_tracker;
/*
Handler object to get the handler_stats from .
Notes :
This pointer is only valid until notify_tables_are_closed ( ) is called .
After that , the tables may be freed or reused , together with their
handler_stats objects .
notify_tables_are_closed ( ) disables printing of FORMAT = JSON output .
r_engine_stats is only printed in FORMAT = JSON output , so we ' re fine .
We do not store pointers to temporary ( aka " work " ) tables here .
Temporary tables may be freed ( e . g . by JOIN : : cleanup ( ) ) or re - created
during query execution ( when HEAP table is converted into Aria ) .
*/
handler *handler_for_stats;
/* When using join buffer: Track the reads from join buffer */
Table_access_tracker jbuf_tracker;
/* When using join buffer: time spent unpacking rows from the join buffer */
Time_and_counter_tracker jbuf_unpack_tracker;
/*
When using join buffer : time spent after unpacking rows from the join
buffer . This will capture the time spent checking the Join Condition :
the condition that depends on this table and preceding tables .
*/
Gap_time_tracker jbuf_extra_time_tracker;
/* When using join buffer: Track the number of incoming record combinations */
Counter_tracker jbuf_loops_tracker;
Explain_rowid_filter *rowid_filter;
int print_explain(select_result_sink *output, uint8 explain_flags,
bool is_analyze,
uint select_id, const char *select_type,
bool using_temporary, bool using_filesort);
void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze);
private :
void append_tag_name(String *str, enum explain_extra_tag tag);
void fill_key_str(String *key_str, bool is_json) const ;
void fill_key_len_str(String *key_len_str, bool is_json) const ;
double get_r_filtered();
void tag_to_json(Json_writer *writer, enum explain_extra_tag tag);
};
/*
EXPLAIN structure for single - table UPDATE .
This is similar to Explain_table_access , except that it is more restrictive .
Also , it can have UPDATE operation options , but currently there aren ' t any .
Explain_delete inherits from this .
*/
class Explain_update : public Explain_node
{
public :
Explain_update(MEM_ROOT *root, bool is_analyze) :
Explain_node(root),
filesort_tracker(NULL),
command_tracker(is_analyze),
handler_for_stats(NULL)
{}
enum explain_node_type get_type() override { return EXPLAIN_UPDATE; }
uint get_select_id() override { return 1 ; /* always root */ }
const char *select_type;
StringBuffer<32 > used_partitions;
String_list used_partitions_list;
bool used_partitions_set;
bool impossible_where;
bool no_partitions;
StringBuffer<64 > table_name;
enum join_type jtype;
String_list possible_keys;
/* Used key when doing a full index scan (possibly with limit) */
Explain_index_use key;
/*
MRR that ' s used with quick select . This should probably belong to the
quick select
*/
StringBuffer<64 > mrr_type;
Explain_quick_select *quick_info;
bool using_where;
Item *where_cond;
ha_rows rows;
bool using_io_buffer;
/* Tracker for doing reads when filling the buffer */
Table_access_tracker buf_tracker;
bool is_using_filesort() { return filesort_tracker? true : false ; }
/*
Non - null value of filesort_tracker means " using filesort "
if we are using filesort , then table_tracker is for the io done inside
filesort .
' tracker ' is for tracking post - filesort reads .
*/
Filesort_tracker *filesort_tracker;
/* ANALYZE members and methods */
Table_access_tracker tracker;
/* This tracks execution of the whole command */
Time_and_counter_tracker command_tracker;
/* TODO: This tracks time to read rows from the table */
Exec_time_tracker table_tracker;
Gap_time_tracker extra_time_tracker;
/* The same as Explain_table_access::handler_for_stats */
handler *handler_for_stats;
int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze) override;
void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze) override;
};
/*
EXPLAIN data structure for an INSERT .
At the moment this doesn ' t do much as we don ' t really have any query plans
for INSERT statements .
*/
class Explain_insert : public Explain_node
{
public :
Explain_insert(MEM_ROOT *root) :
Explain_node(root)
{}
StringBuffer<64 > table_name;
enum explain_node_type get_type() override { return EXPLAIN_INSERT; }
uint get_select_id() override { return 1 ; /* always root */ }
int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze) override;
void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze) override;
};
/*
EXPLAIN data of a single - table DELETE .
*/
class Explain_delete: public Explain_update
{
public :
Explain_delete(MEM_ROOT *root, bool is_analyze) :
Explain_update(root, is_analyze)
{}
/*
TRUE means we ' re going to call handler - > delete_all_rows ( ) and not read any
rows .
*/
bool deleting_all_rows;
enum explain_node_type get_type() override { return EXPLAIN_DELETE; }
uint get_select_id() override { return 1 ; /* always root */ }
int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze) override;
void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze) override;
};
/*
EXPLAIN data structure for subquery materialization .
All decisions are made at execution time so here we just store the tracker
that has all the info .
*/
class Explain_subq_materialization : public Sql_alloc
{
public :
Explain_subq_materialization(MEM_ROOT *mem_root)
: tracker(mem_root)
{}
Subq_materialization_tracker *get_tracker() { return &tracker; }
void print_explain_json(Json_writer *writer, bool is_analyze);
private :
Subq_materialization_tracker tracker;
};
#endif //SQL_EXPLAIN_INCLUDED
Messung V0.5 in Prozent C=91 H=100 G=95
¤ Dauer der Verarbeitung: 0.21 Sekunden
(vorverarbeitet am 2026-10-08)
¤
*© Formatika GbR, Deutschland
2026-10-09
Neuigkeiten
Aktuelles
Motto des Tages
Open Source Software
Jenseits des Üblichen ....
Besucherstatistik
Statistik
#Sources=1126438
#Domains=1867298