diff --git a/mysql-test/r/partition_pruning.result b/mysql-test/r/partition_pruning.result index 6f210a76778..6f274cb191a 100644 --- a/mysql-test/r/partition_pruning.result +++ b/mysql-test/r/partition_pruning.result @@ -304,3 +304,42 @@ id select_type table partitions type possible_keys key key_len ref rows Extra explain partitions select * from t1 where b > 1 and b < 3 and (a =1 or a =2); id select_type table partitions type possible_keys key key_len ref rows Extra 1 SIMPLE t1 p1_sp2,p2_sp2 ALL NULL NULL NULL NULL 3 Using where +drop table t1; +create table t1 (a int) partition by list(a) ( +partition p0 values in (1,2), +partition p1 values in (3,4) +); +insert into t1 values (1),(1),(2),(2),(3),(4),(3),(4); +flush status; +update t1 set a=100 where a=5; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +flush status; +update t1 set a=100 where a+1=5+1; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 10 +flush status; +delete from t1 where a=5; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +flush status; +delete from t1 where a+1=5+1; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 10 +create table t2 like t1; +insert into t2 select * from t2; +flush status; +update t1,t2 set t1.a=1000, t2.a=1000 where t1.a=5 and t2.a=5; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 3 +flush status; +delete t1,t2 from t1, t2 where t1.a=5 and t2.a=5; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 3 +drop table t1,t2; diff --git a/mysql-test/t/partition_pruning.test b/mysql-test/t/partition_pruning.test index b45e6cf0d76..45717e11b3e 100644 --- a/mysql-test/t/partition_pruning.test +++ b/mysql-test/t/partition_pruning.test @@ -269,6 +269,52 @@ insert into t1 values (1,1),(2,2),(3,3); explain partitions select * from t1 where b > 1 and b < 3; explain partitions select * from t1 where b > 1 and b < 3 and (a =1 or a =2); +drop table t1; + +# Test partition pruning for single-table UPDATE/DELETE. +# TODO: Currently we test only "all partitions pruned away" case. Add more +# tests when the patch that makes use of partition pruning results at +# execution phase is pushed. + +create table t1 (a int) partition by list(a) ( + partition p0 values in (1,2), + partition p1 values in (3,4) +); +insert into t1 values (1),(1),(2),(2),(3),(4),(3),(4); + +# This won't do any table access +flush status; +update t1 set a=100 where a=5; +show status like 'Handler_read_rnd_next'; + +# ... as compared to this, which will scan both partitions +flush status; +update t1 set a=100 where a+1=5+1; +show status like 'Handler_read_rnd_next'; + +# Same as above for DELETE: +flush status; +delete from t1 where a=5; +show status like 'Handler_read_rnd_next'; + +flush status; +delete from t1 where a+1=5+1; +show status like 'Handler_read_rnd_next'; + +# Same as above multi-table UPDATE/DELETE +create table t2 like t1; +insert into t2 select * from t2; + +flush status; +update t1,t2 set t1.a=1000, t2.a=1000 where t1.a=5 and t2.a=5; +show status like 'Handler_read_rnd_next'; +# ^ This shows 3 accesses, these are caused by const table reads. +# They should vanish when partition pruning results are used. + +flush status; +delete t1,t2 from t1, t2 where t1.a=5 and t2.a=5; +show status like 'Handler_read_rnd_next'; +drop table t1,t2; # No tests for NULLs in RANGE(monotonic_expr()) - they depend on BUG#15447 # being fixed. diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 7d8f8f12383..f4c857f3785 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -100,6 +100,21 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, /* Handler didn't support fast delete; Delete rows one by one */ } +#ifdef WITH_PARTITION_STORAGE_ENGINE + if (prune_partitions(thd, table, conds)) + { + free_underlaid_joins(thd, select_lex); + thd->row_count_func= 0; + send_ok(thd); // No matching records + DBUG_RETURN(0); + } + /* + Update the table->records number (note: we probably could remove the + previous file->info() call) + */ + table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); +#endif + table->used_keys.clear_all(); table->quick_keys.clear_all(); // Can't use 'only index' select=make_select(table, 0, 0, conds, 0, &error); @@ -111,13 +126,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, free_underlaid_joins(thd, select_lex); thd->row_count_func= 0; send_ok(thd,0L); - /* We don't need to call reset_auto_increment in this case, because mysql_truncate always gives a NULL conds argument, hence we never get here. */ - DBUG_RETURN(0); // Nothing to delete } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 62ea4e89eff..ab383241a28 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -244,6 +244,21 @@ int mysql_update(THD *thd, } // Don't count on usage of 'only index' when calculating which key to use table->used_keys.clear_all(); + +#ifdef WITH_PARTITION_STORAGE_ENGINE + if (prune_partitions(thd, table, conds)) + { + free_underlaid_joins(thd, select_lex); + send_ok(thd); // No matching records + DBUG_RETURN(0); + } + /* + Update the table->records number (note: we probably could remove the + previous file->info() call) + */ + table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); +#endif + select= make_select(table, 0, 0, conds, 0, &error); if (error || !limit || (select && select->check_quick(thd, safe_update, limit)))