MDEV-3798: EXPLAIN UPDATE/DELETE
- Generate correct contents of `Extra` column for UPDATEs/DELETEs that use quick selects - UPDATEs with used_key_is_modified=true will show "Using buffer"
This commit is contained in:
parent
69e6a2bb22
commit
161d687594
@ -142,14 +142,16 @@ void Update_plan::save_explain_data_intern(Explain_query *query,
|
|||||||
|
|
||||||
explain->using_where= test(select && select->cond);
|
explain->using_where= test(select && select->cond);
|
||||||
explain->using_filesort= using_filesort;
|
explain->using_filesort= using_filesort;
|
||||||
|
explain->using_io_buffer= using_io_buffer;
|
||||||
|
|
||||||
make_possible_keys_line(table, possible_keys, &explain->possible_keys_line);
|
make_possible_keys_line(table, possible_keys, &explain->possible_keys_line);
|
||||||
|
|
||||||
|
explain->quick_info= NULL;
|
||||||
|
|
||||||
/* Calculate key_len */
|
/* Calculate key_len */
|
||||||
if (select && select->quick)
|
if (select && select->quick)
|
||||||
{
|
{
|
||||||
select->quick->add_keys_and_lengths(&explain->key_str,
|
explain->quick_info= select->quick->get_explain(mem_root);
|
||||||
&explain->key_len_str);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -218,7 +220,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
|
|||||||
killed_state killed_status= NOT_KILLED;
|
killed_state killed_status= NOT_KILLED;
|
||||||
THD::enum_binlog_query_type query_type= THD::ROW_QUERY_TYPE;
|
THD::enum_binlog_query_type query_type= THD::ROW_QUERY_TYPE;
|
||||||
bool with_select= !select_lex->item_list.is_empty();
|
bool with_select= !select_lex->item_list.is_empty();
|
||||||
Delete_plan query_plan;
|
Delete_plan query_plan(thd->mem_root);
|
||||||
query_plan.index= MAX_KEY;
|
query_plan.index= MAX_KEY;
|
||||||
query_plan.using_filesort= FALSE;
|
query_plan.using_filesort= FALSE;
|
||||||
DBUG_ENTER("mysql_delete");
|
DBUG_ENTER("mysql_delete");
|
||||||
|
@ -793,6 +793,8 @@ int Explain_update::print_explain(Explain_query *query,
|
|||||||
select_result_sink *output,
|
select_result_sink *output,
|
||||||
uint8 explain_flags)
|
uint8 explain_flags)
|
||||||
{
|
{
|
||||||
|
StringBuffer<64> key_buf;
|
||||||
|
StringBuffer<64> key_len_buf;
|
||||||
StringBuffer<64> extra_str;
|
StringBuffer<64> extra_str;
|
||||||
if (impossible_where || no_partitions)
|
if (impossible_where || no_partitions)
|
||||||
{
|
{
|
||||||
@ -807,8 +809,32 @@ int Explain_update::print_explain(Explain_query *query,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (quick_info)
|
||||||
|
{
|
||||||
|
quick_info->print_key(&key_buf);
|
||||||
|
quick_info->print_key_len(&key_len_buf);
|
||||||
|
|
||||||
|
StringBuffer<64> quick_buf;
|
||||||
|
quick_info->print_extra(&quick_buf);
|
||||||
|
if (quick_buf.length())
|
||||||
|
{
|
||||||
|
extra_str.append(STRING_WITH_LEN("Using "));
|
||||||
|
extra_str.append(quick_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
key_buf.copy(key_str);
|
||||||
|
key_len_buf.copy(key_len_str);
|
||||||
|
}
|
||||||
|
|
||||||
if (using_where)
|
if (using_where)
|
||||||
|
{
|
||||||
|
if (extra_str.length() !=0)
|
||||||
|
extra_str.append(STRING_WITH_LEN("; "));
|
||||||
extra_str.append(STRING_WITH_LEN("Using where"));
|
extra_str.append(STRING_WITH_LEN("Using where"));
|
||||||
|
}
|
||||||
|
|
||||||
if (mrr_type.length() != 0)
|
if (mrr_type.length() != 0)
|
||||||
{
|
{
|
||||||
@ -816,7 +842,7 @@ int Explain_update::print_explain(Explain_query *query,
|
|||||||
extra_str.append(STRING_WITH_LEN("; "));
|
extra_str.append(STRING_WITH_LEN("; "));
|
||||||
extra_str.append(mrr_type);
|
extra_str.append(mrr_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (using_filesort)
|
if (using_filesort)
|
||||||
{
|
{
|
||||||
if (extra_str.length() !=0)
|
if (extra_str.length() !=0)
|
||||||
@ -824,6 +850,13 @@ int Explain_update::print_explain(Explain_query *query,
|
|||||||
extra_str.append(STRING_WITH_LEN("Using filesort"));
|
extra_str.append(STRING_WITH_LEN("Using filesort"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (using_io_buffer)
|
||||||
|
{
|
||||||
|
if (extra_str.length() !=0)
|
||||||
|
extra_str.append(STRING_WITH_LEN("; "));
|
||||||
|
extra_str.append(STRING_WITH_LEN("Using buffer"));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Single-table DELETE commands do not do "Using temporary".
|
Single-table DELETE commands do not do "Using temporary".
|
||||||
"Using index condition" is also not possible (which is an unjustified limitation)
|
"Using index condition" is also not possible (which is an unjustified limitation)
|
||||||
@ -836,8 +869,8 @@ int Explain_update::print_explain(Explain_query *query,
|
|||||||
used_partitions_set? used_partitions.c_ptr() : NULL,
|
used_partitions_set? used_partitions.c_ptr() : NULL,
|
||||||
jtype,
|
jtype,
|
||||||
possible_keys_line.length()? possible_keys_line.c_ptr(): NULL,
|
possible_keys_line.length()? possible_keys_line.c_ptr(): NULL,
|
||||||
key_str.length()? key_str.c_ptr() : NULL,
|
key_buf.length()? key_buf.c_ptr() : NULL,
|
||||||
key_len_str.length() ? key_len_str.c_ptr() : NULL,
|
key_len_buf.length() ? key_len_buf.c_ptr() : NULL,
|
||||||
NULL, /* 'ref' is always NULL in single-table EXPLAIN DELETE */
|
NULL, /* 'ref' is always NULL in single-table EXPLAIN DELETE */
|
||||||
&rows,
|
&rows,
|
||||||
extra_str.c_ptr());
|
extra_str.c_ptr());
|
||||||
@ -846,7 +879,8 @@ int Explain_update::print_explain(Explain_query *query,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int Explain_insert::print_explain(Explain_query *query, select_result_sink *output,
|
int Explain_insert::print_explain(Explain_query *query,
|
||||||
|
select_result_sink *output,
|
||||||
uint8 explain_flags)
|
uint8 explain_flags)
|
||||||
{
|
{
|
||||||
const char *select_type="INSERT";
|
const char *select_type="INSERT";
|
||||||
|
@ -486,10 +486,13 @@ public:
|
|||||||
StringBuffer<128> key_len_str;
|
StringBuffer<128> key_len_str;
|
||||||
StringBuffer<64> mrr_type;
|
StringBuffer<64> mrr_type;
|
||||||
|
|
||||||
|
Explain_quick_select *quick_info;
|
||||||
|
|
||||||
bool using_where;
|
bool using_where;
|
||||||
ha_rows rows;
|
ha_rows rows;
|
||||||
|
|
||||||
bool using_filesort;
|
bool using_filesort;
|
||||||
|
bool using_io_buffer;
|
||||||
|
|
||||||
virtual int print_explain(Explain_query *query, select_result_sink *output,
|
virtual int print_explain(Explain_query *query, select_result_sink *output,
|
||||||
uint8 explain_flags);
|
uint8 explain_flags);
|
||||||
|
@ -2390,6 +2390,9 @@ public:
|
|||||||
select should not be shown when printing EXPLAIN.
|
select should not be shown when printing EXPLAIN.
|
||||||
*/
|
*/
|
||||||
bool updating_a_view;
|
bool updating_a_view;
|
||||||
|
|
||||||
|
/* Allocate things there */
|
||||||
|
MEM_ROOT *mem_root;
|
||||||
|
|
||||||
TABLE *table;
|
TABLE *table;
|
||||||
SQL_SELECT *select;
|
SQL_SELECT *select;
|
||||||
@ -2403,6 +2406,7 @@ public:
|
|||||||
|
|
||||||
key_map possible_keys;
|
key_map possible_keys;
|
||||||
bool using_filesort;
|
bool using_filesort;
|
||||||
|
bool using_io_buffer;
|
||||||
|
|
||||||
/* Set this plan to be a plan to do nothing because of impossible WHERE */
|
/* Set this plan to be a plan to do nothing because of impossible WHERE */
|
||||||
void set_impossible_where() { impossible_where= true; }
|
void set_impossible_where() { impossible_where= true; }
|
||||||
@ -2412,8 +2416,10 @@ public:
|
|||||||
void save_explain_data_intern(Explain_query *query, Explain_update *eu);
|
void save_explain_data_intern(Explain_query *query, Explain_update *eu);
|
||||||
virtual ~Update_plan() {}
|
virtual ~Update_plan() {}
|
||||||
|
|
||||||
Update_plan() :
|
Update_plan(MEM_ROOT *mem_root_arg) :
|
||||||
impossible_where(false), no_partitions(false), using_filesort(false)
|
impossible_where(false), no_partitions(false),
|
||||||
|
mem_root(mem_root_arg),
|
||||||
|
using_filesort(false), using_io_buffer(false)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2425,8 +2431,10 @@ class Delete_plan : public Update_plan
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
/* Construction functions */
|
/* Construction functions */
|
||||||
Delete_plan() :
|
Delete_plan(MEM_ROOT *mem_root_arg) :
|
||||||
deleting_all_rows(false) {}
|
Update_plan(mem_root_arg),
|
||||||
|
deleting_all_rows(false)
|
||||||
|
{}
|
||||||
|
|
||||||
/* Set this query plan to be a plan to make a call to h->delete_all_rows() */
|
/* Set this query plan to be a plan to make a call to h->delete_all_rows() */
|
||||||
void set_delete_all_rows(ha_rows rows_arg)
|
void set_delete_all_rows(ha_rows rows_arg)
|
||||||
|
@ -276,7 +276,7 @@ int mysql_update(THD *thd,
|
|||||||
ulonglong id;
|
ulonglong id;
|
||||||
List<Item> all_fields;
|
List<Item> all_fields;
|
||||||
killed_state killed_status= NOT_KILLED;
|
killed_state killed_status= NOT_KILLED;
|
||||||
Update_plan query_plan;
|
Update_plan query_plan(thd->mem_root);
|
||||||
query_plan.index= MAX_KEY;
|
query_plan.index= MAX_KEY;
|
||||||
query_plan.using_filesort= FALSE;
|
query_plan.using_filesort= FALSE;
|
||||||
bool apc_target_enabled= false; // means was enabled *by code this function*
|
bool apc_target_enabled= false; // means was enabled *by code this function*
|
||||||
@ -495,6 +495,17 @@ int mysql_update(THD *thd,
|
|||||||
query_plan.table_rows= table->file->stats.records;
|
query_plan.table_rows= table->file->stats.records;
|
||||||
query_plan.possible_keys= select? select->possible_keys: key_map(0);
|
query_plan.possible_keys= select? select->possible_keys: key_map(0);
|
||||||
|
|
||||||
|
if (used_key_is_modified || order ||
|
||||||
|
partition_key_modified(table, table->write_set))
|
||||||
|
{
|
||||||
|
if (order && (need_sort || used_key_is_modified))
|
||||||
|
query_plan.using_filesort= true;
|
||||||
|
else
|
||||||
|
query_plan.using_io_buffer= true;
|
||||||
|
}
|
||||||
|
|
||||||
|
query_plan.save_explain_data(thd->lex->explain);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Ok, we have generated a query plan for the UPDATE.
|
Ok, we have generated a query plan for the UPDATE.
|
||||||
- if we're running EXPLAIN UPDATE, goto produce explain output
|
- if we're running EXPLAIN UPDATE, goto produce explain output
|
||||||
@ -502,16 +513,12 @@ int mysql_update(THD *thd,
|
|||||||
*/
|
*/
|
||||||
if (thd->lex->describe)
|
if (thd->lex->describe)
|
||||||
goto exit_without_my_ok;
|
goto exit_without_my_ok;
|
||||||
|
|
||||||
query_plan.save_explain_data(thd->lex->explain);
|
|
||||||
thd->apc_target.enable();
|
thd->apc_target.enable();
|
||||||
apc_target_enabled= true;
|
apc_target_enabled= true;
|
||||||
DBUG_EXECUTE_IF("show_explain_probe_update_exec_start",
|
DBUG_EXECUTE_IF("show_explain_probe_update_exec_start",
|
||||||
dbug_serve_apcs(thd, 1););
|
dbug_serve_apcs(thd, 1););
|
||||||
|
|
||||||
|
if (query_plan.using_filesort || query_plan.using_io_buffer)
|
||||||
if (used_key_is_modified || order ||
|
|
||||||
partition_key_modified(table, table->write_set))
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
We can't update table directly; We must first search after all
|
We can't update table directly; We must first search after all
|
||||||
@ -528,7 +535,7 @@ int mysql_update(THD *thd,
|
|||||||
table->use_all_columns();
|
table->use_all_columns();
|
||||||
|
|
||||||
/* note: We avoid sorting if we sort on the used index */
|
/* note: We avoid sorting if we sort on the used index */
|
||||||
if (order && (need_sort || used_key_is_modified))
|
if (query_plan.using_filesort)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Doing an ORDER BY; Let filesort find and sort the rows we are going
|
Doing an ORDER BY; Let filesort find and sort the rows we are going
|
||||||
@ -1034,7 +1041,6 @@ err:
|
|||||||
|
|
||||||
exit_without_my_ok:
|
exit_without_my_ok:
|
||||||
DBUG_ASSERT(!apc_target_enabled);
|
DBUG_ASSERT(!apc_target_enabled);
|
||||||
query_plan.save_explain_data(thd->lex->explain);
|
|
||||||
|
|
||||||
int err2= thd->lex->explain->send_explain(thd);
|
int err2= thd->lex->explain->send_explain(thd);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user