Commit 161d6875 authored by Sergey Petrunya's avatar Sergey Petrunya

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"
parent 69e6a2bb
...@@ -142,14 +142,16 @@ void Update_plan::save_explain_data_intern(Explain_query *query, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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 ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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: ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment