diff options
author | Sergei Golubchik <serg@mariadb.org> | 2017-07-07 19:55:31 +0200 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2017-07-07 22:38:15 +0200 |
commit | c65cce3698edde272b8452c1fecec3d9522cea6e (patch) | |
tree | bddc69fadd7a800aaf0cea2d7cdc3e3008db0e8a /sql/sql_delete.cc | |
parent | abf95afa2a1c23f3c7aa42f44fc665450ebeeea1 (diff) | |
download | mariadb-git-c65cce3698edde272b8452c1fecec3d9522cea6e.tar.gz |
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).
Diffstat (limited to 'sql/sql_delete.cc')
-rw-r--r-- | sql/sql_delete.cc | 102 |
1 files changed, 48 insertions, 54 deletions
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 8d4757e6d31..a9275bd39fd 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -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,13 +262,13 @@ 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); - query_plan.index= MAX_KEY; - query_plan.using_filesort= FALSE; Unique * deltempfile= NULL; - uint delete_while_scanning= 1; - uint delete_record= 0; + bool delete_record, delete_while_scanning; DBUG_ENTER("mysql_delete"); + query_plan.index= MAX_KEY; + query_plan.using_filesort= FALSE; + create_explain_query(thd->lex, thd->mem_root); if (open_and_lock_tables(thd, table_list, TRUE, 0)) DBUG_RETURN(TRUE); @@ -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); |