#At file:///data0/magnus/mysql/trunk-wl5906-rbwr/ based on revid:jon.hauglid@stripped
3187 magnus.blaudd@stripped 2011-06-10
WL#5906 read before write removal (RBWR)
- Make it possible for storage engines to optimize away
read of record before UPDATE/DELETE in order to save
roundtrips and allow for batching.
modified:
sql/handler.h
sql/sql_delete.cc
sql/sql_update.cc
=== modified file 'sql/handler.h'
--- a/sql/handler.h 2011-06-01 09:11:28 +0000
+++ b/sql/handler.h 2011-06-10 10:24:29 +0000
@@ -1796,6 +1796,28 @@ public:
virtual int extra_opt(enum ha_extra_function operation, ulong cache_size)
{ return extra(operation); }
+ /*
+ Informs the handler if this handler support read removal
+ (could use table_flags, but patch is smaller this way)
+ */
+ virtual bool read_before_write_removal_supported(void) const
+ { return false; }
+
+ /*
+ Informs handler that it is possible to optimise away the real read
+ operation from the handler for the current table and instead
+ use a generated read to optimise simple UPDATE and DELETEs.
+ */
+ virtual bool read_before_write_removal_possible(void)
+ { return false; }
+
+ /*
+ Return the number of rows the handler has written while using
+ read before write removal
+ */
+ virtual ha_rows read_before_write_removal_rows_written(void) const
+ { DBUG_ASSERT(0); return (ha_rows) 0; }
+
/**
In an UPDATE or DELETE, if the row under the cursor was locked by another
transaction, and the engine used an optimistic read of the last
=== modified file 'sql/sql_delete.cc'
--- a/sql/sql_delete.cc 2011-05-26 15:20:09 +0000
+++ b/sql/sql_delete.cc 2011-06-10 10:24:29 +0000
@@ -59,6 +59,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *
bool const_cond_result;
ha_rows deleted= 0;
bool reverse= FALSE;
+ bool read_removal= false;
bool skip_record;
ORDER *order= (ORDER *) ((order_list && order_list->elements) ?
order_list->first : NULL);
@@ -293,6 +294,31 @@ bool mysql_delete(THD *thd, TABLE_LIST *
else
will_batch= !table->file->start_bulk_delete();
+ /*
+ Read removal is possible if the selected quick read
+ method is using full unique index
+ */
+ if (select && select->quick &&
+ will_batch &&
+ !using_limit &&
+ table->file->read_before_write_removal_supported())
+ {
+ const uint idx = select->quick->index;
+ DBUG_PRINT("rbwr", ("checking index: %d", idx));
+ const KEY *key= table->key_info + idx;
+ if ((key->flags & HA_NOSAME) == HA_NOSAME)
+ {
+ DBUG_PRINT("rbwr", ("index is unique"));
+ bitmap_clear_all(&table->tmp_set);
+ table->mark_columns_used_by_index_no_reset(idx, &table->tmp_set);
+ if (bitmap_cmp(&table->tmp_set, table->read_set))
+ {
+ DBUG_PRINT("rbwr", ("using whole index, rbwr possible"));
+ read_removal=
+ table->file->read_before_write_removal_possible();
+ }
+ }
+ }
table->mark_columns_needed_for_delete();
@@ -355,6 +381,13 @@ bool mysql_delete(THD *thd, TABLE_LIST *
table->file->print_error(loc_error,MYF(0));
error=1;
}
+ if (read_removal)
+ {
+ /* Only handler knows how many records really was written */
+ DBUG_PRINT("rbwr", ("old deleted: %ld", (long)deleted));
+ deleted= table->file->read_before_write_removal_rows_written();
+ DBUG_PRINT("rbwr", ("really deleted: %ld", (long)deleted));
+ }
THD_STAGE_INFO(thd, stage_end);
end_read_record(&info);
if (options & OPTION_QUICK)
=== modified file 'sql/sql_update.cc'
--- a/sql/sql_update.cc 2011-06-09 08:58:41 +0000
+++ b/sql/sql_update.cc 2011-06-10 10:24:29 +0000
@@ -158,6 +158,37 @@ static bool check_fields(THD *thd, List<
}
+/*
+ Check if all expressions in list are constant expressions
+
+ SYNOPSIS
+ check_constant_expressions()
+ values List of expressions
+
+ RETURN
+ TRUE Only constant expressions
+ FALSE At least one non-constant expression
+*/
+
+static bool check_constant_expressions(List<Item> &values)
+{
+ Item *value;
+ List_iterator_fast<Item> v(values);
+ DBUG_ENTER("check_constant_expressions");
+
+ while ((value= v++))
+ {
+ if (!value->const_item())
+ {
+ DBUG_PRINT("exit", ("expression is not constant"));
+ DBUG_RETURN(FALSE);
+ }
+ }
+ DBUG_PRINT("exit", ("expression is constant"));
+ DBUG_RETURN(TRUE);
+}
+
+
/**
Re-read record if more columns are needed for error message.
@@ -423,6 +454,36 @@ int mysql_update(THD *thd,
DBUG_RETURN(0);
}
+ /*
+ Read removal is possible if the selected quick read
+ method is using full unique index
+
+ NOTE! table->read_set currently holds the columns which are
+ used for the WHERE clause(this info is most likely already
+ available in select->quick, but where?)
+ */
+ bool read_removal= false;
+ if (select && select->quick &&
+ !ignore &&
+ !using_limit &&
+ table->file->read_before_write_removal_supported())
+ {
+ const uint idx= select->quick->index;
+ DBUG_PRINT("rbwr", ("checking index: %d", idx));
+ const KEY *key= table->key_info + idx;
+ if ((key->flags & HA_NOSAME) == HA_NOSAME)
+ {
+ DBUG_PRINT("rbwr", ("index is unique"));
+ bitmap_clear_all(&table->tmp_set);
+ table->mark_columns_used_by_index_no_reset(idx, &table->tmp_set);
+ if (bitmap_cmp(&table->tmp_set, table->read_set))
+ {
+ DBUG_PRINT("rbwr", ("using full index, rbwr possible"));
+ read_removal= true;
+ }
+ }
+ }
+
/* If running in safe sql mode, don't allow updates without keys */
if (table->quick_keys.is_clear_all())
{
@@ -595,6 +656,10 @@ int mysql_update(THD *thd,
}
if (table->key_read)
table->restore_column_maps_after_mark_index();
+
+ /* Rows are already read -> not possible to remove */
+ DBUG_PRINT("rbwr", ("rows are already read, turning off rbwr"));
+ read_removal= false;
}
if (ignore)
@@ -634,6 +699,14 @@ int mysql_update(THD *thd,
else
will_batch= !table->file->start_bulk_update();
+ if (read_removal &&
+ will_batch &&
+ check_constant_expressions(values))
+ {
+ assert(select && select->quick);
+ read_removal= table->file->read_before_write_removal_possible();
+ }
+
/*
Assure that we can use position()
if we need to create an error message.
@@ -840,6 +913,20 @@ int mysql_update(THD *thd,
table->file->end_bulk_update();
table->file->try_semi_consistent_read(0);
+ if (read_removal)
+ {
+ /* Only handler knows how many records really was written */
+ DBUG_PRINT("rbwr", ("adjusting updated: %ld, found: %ld",
+ (long)updated, (long)found));
+
+ updated= table->file->read_before_write_removal_rows_written();
+ if (!records_are_comparable(table))
+ found= updated;
+
+ DBUG_PRINT("rbwr", ("really updated: %ld, found: %ld",
+ (long)updated, (long)found));
+ }
+
if (!transactional_table && updated > 0)
thd->transaction.stmt.mark_modified_non_trans_table();
Attachment: [text/bzr-bundle] bzr/magnus.blaudd@oracle.com-20110610102429-nav9ppjwmf59u6xw.bundle
| Thread |
|---|
| • bzr commit into mysql-trunk branch (magnus.blaudd:3187) WL#5906 | magnus.blaudd | 10 Jun |