1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

MDEV-12137 DELETE statement with the same source and target

* various cleanups (mostly cosmetic)
* remove useless tests (that were tesing the error condition)
* optimize delete_use_source test (from 6 mins to 50 seconds,
  mainly by removing two huge rollbacks at the end).
This commit is contained in:
Sergei Golubchik
2017-07-07 19:55:31 +02:00
parent abf95afa2a
commit c65cce3698
11 changed files with 173 additions and 365 deletions

View File

@ -45,7 +45,7 @@
// end_read_record
#include "sql_partition.h" // make_used_partitions_str
#define MEM_STRIP_BUF_SIZE current_thd->variables.sortbuff_size
#define MEM_STRIP_BUF_SIZE thd->variables.sortbuff_size
/*
@brief
@ -214,6 +214,22 @@ void Update_plan::save_explain_data_intern(MEM_ROOT *mem_root,
}
static bool record_should_be_deleted(THD *thd, TABLE *table, SQL_SELECT *sel,
Explain_delete *explain)
{
explain->tracker.on_record_read();
thd->inc_examined_row_count(1);
if (table->vfield)
(void) table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_DELETE);
if (!sel || sel->skip_record(thd) > 0)
{
explain->tracker.on_record_after_where();
return true;
}
return false;
}
/**
Implement DELETE SQL word.
@ -246,12 +262,12 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
bool with_select= !select_lex->item_list.is_empty();
Explain_delete *explain;
Delete_plan query_plan(thd->mem_root);
Unique * deltempfile= NULL;
bool delete_record, delete_while_scanning;
DBUG_ENTER("mysql_delete");
query_plan.index= MAX_KEY;
query_plan.using_filesort= FALSE;
Unique * deltempfile= NULL;
uint delete_while_scanning= 1;
uint delete_record= 0;
DBUG_ENTER("mysql_delete");
create_explain_query(thd->lex, thd->mem_root);
if (open_and_lock_tables(thd, table_list, TRUE, 0))
@ -281,7 +297,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (mysql_prepare_delete(thd, table_list, select_lex->with_wild,
select_lex->item_list, &conds,
delete_while_scanning))
&delete_while_scanning))
DBUG_RETURN(TRUE);
if (with_select)
@ -562,67 +578,47 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
explain= (Explain_delete*)thd->lex->explain->get_upd_del_plan();
explain->tracker.on_scan_init();
if (delete_while_scanning == 0)
if (!delete_while_scanning)
{
/*
The table we are going to delete appears in join.
Instead of deleting the rows, first mark them deleted.
The table we are going to delete appears in subqueries in the where
clause. Instead of deleting the rows, first mark them deleted.
*/
ha_rows tmplimit=limit;
deltempfile= new Unique (refpos_order_cmp,
(void *) table->file,
table->file->ref_length,
MEM_STRIP_BUF_SIZE);
deltempfile= new (thd->mem_root) Unique (refpos_order_cmp, table->file,
table->file->ref_length,
MEM_STRIP_BUF_SIZE);
while (!(error=info.read_record(&info)) && !thd->killed &&
! thd->is_error())
{
explain->tracker.on_record_read();
thd->inc_examined_row_count(1);
if (table->vfield)
(void) table->update_virtual_fields(table->file,
VCOL_UPDATE_FOR_DELETE);
if (!select || select->skip_record(thd) > 0)
if (record_should_be_deleted(thd, table, select, explain))
{
explain->tracker.on_record_after_where();
table->file->position(table->record[0]);
if ((error= deltempfile->unique_add((char*) table->file->ref)))
{
error= 1;
goto terminate_delete;
}
if (!--tmplimit && using_limit)
{
break;
}
if (!--tmplimit && using_limit)
break;
}
}
end_read_record(&info);
if (deltempfile->get(table) ||
table->file->ha_index_or_rnd_end() ||
init_read_record(&info, thd, table, NULL , &deltempfile->sort, 0, 1,
FALSE))
if (deltempfile->get(table) || table->file->ha_index_or_rnd_end() ||
init_read_record(&info, thd, table, 0, &deltempfile->sort, 0, 1, false))
{
error= 1;
goto terminate_delete;
}
delete_record= 1;
delete_record= true;
}
while (!(error=info.read_record(&info)) && !thd->killed &&
! thd->is_error())
{
if (delete_while_scanning == 1)
{
explain->tracker.on_record_read();
thd->inc_examined_row_count(1);
if (table->vfield)
(void) table->update_virtual_fields(table->file,
VCOL_UPDATE_FOR_DELETE);
delete_record=(!select || select->skip_record(thd) > 0) ? 1 : 0;
if (delete_record)
explain->tracker.on_record_after_where();
}
if (delete_record == 1)
if (delete_while_scanning)
delete_record= record_should_be_deleted(thd, table, select, explain);
if (delete_record)
{
if (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
@ -808,13 +804,14 @@ l
*/
int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list,
uint wild_num, List<Item> &field_list, Item **conds,
uint &delete_while_scanning)
bool *delete_while_scanning)
{
Item *fake_conds= 0;
SELECT_LEX *select_lex= &thd->lex->select_lex;
DBUG_ENTER("mysql_prepare_delete");
List<Item> all_fields;
*delete_while_scanning= true;
thd->lex->allow_sum_func= 0;
if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
&thd->lex->select_lex.top_join_list,
@ -834,11 +831,9 @@ l
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE");
DBUG_RETURN(TRUE);
}
{
TABLE_LIST *duplicate;
if ((duplicate= unique_table(thd, table_list, table_list->next_global, 0)))
delete_while_scanning= 0;
}
if (unique_table(thd, table_list, table_list->next_global, 0))
*delete_while_scanning= false;
if (select_lex->inner_refs_list.elements &&
fix_inner_refs(thd, all_fields, select_lex, select_lex->ref_pointer_array))
@ -1002,7 +997,7 @@ multi_delete::initialize_tables(JOIN *join)
DBUG_RETURN(1);
table_map tables_to_delete_from=0;
delete_while_scanning= 1;
delete_while_scanning= true;
for (walk= delete_tables; walk; walk= walk->next_local)
{
TABLE_LIST *tbl= walk->correspondent_table->find_table_for_update();
@ -1015,7 +1010,7 @@ multi_delete::initialize_tables(JOIN *join)
in join, we need to defer delete. So the delete
doesn't interfers with the scaning of results.
*/
delete_while_scanning= 0;
delete_while_scanning= false;
}
}
@ -1051,7 +1046,7 @@ multi_delete::initialize_tables(JOIN *join)
case send_data() shouldn't delete any rows a we may touch
the rows in the deleted table many times
*/
delete_while_scanning= 0;
delete_while_scanning= false;
}
}
walk= delete_tables;
@ -1064,10 +1059,9 @@ multi_delete::initialize_tables(JOIN *join)
for (;walk ;walk= walk->next_local)
{
TABLE *table=walk->table;
*tempfiles_ptr++= new Unique (refpos_order_cmp,
(void *) table->file,
table->file->ref_length,
MEM_STRIP_BUF_SIZE);
*tempfiles_ptr++= new (thd->mem_root) Unique (refpos_order_cmp, table->file,
table->file->ref_length,
MEM_STRIP_BUF_SIZE);
}
init_ftfuncs(thd, thd->lex->current_select, 1);
DBUG_RETURN(thd->is_fatal_error != 0);