Commit cc900f2c authored by Mattias Jonsson's avatar Mattias Jonsson

Bug#35845: unneccesary call to ha_start_bulk_insert for not used partitions

(Backport)

Problem is that when insert (ha_start_bulk_insert) in i partitioned table,
it will call ha_start_bulk_insert for every partition, used or not.

Solution is to delay the call to the partitions ha_start_bulk_insert until
the first row is to be inserted into that partition
parent 510eac6e
...@@ -239,6 +239,7 @@ void ha_partition::init_handler_variables() ...@@ -239,6 +239,7 @@ void ha_partition::init_handler_variables()
m_curr_key_info[0]= NULL; m_curr_key_info[0]= NULL;
m_curr_key_info[1]= NULL; m_curr_key_info[1]= NULL;
is_clone= FALSE, is_clone= FALSE,
m_part_func_monotonicity_info= NON_MONOTONIC;
auto_increment_lock= FALSE; auto_increment_lock= FALSE;
auto_increment_safe_stmt_log_lock= FALSE; auto_increment_safe_stmt_log_lock= FALSE;
/* /*
...@@ -2464,11 +2465,18 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) ...@@ -2464,11 +2465,18 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
} }
} }
/* Initialize the bitmap we use to minimize ha_start_bulk_insert calls */
if (bitmap_init(&m_bulk_insert_started, NULL, m_tot_parts + 1, FALSE))
DBUG_RETURN(1);
bitmap_clear_all(&m_bulk_insert_started);
/* Initialize the bitmap we use to determine what partitions are used */ /* Initialize the bitmap we use to determine what partitions are used */
if (!is_clone) if (!is_clone)
{ {
if (bitmap_init(&(m_part_info->used_partitions), NULL, m_tot_parts, TRUE)) if (bitmap_init(&(m_part_info->used_partitions), NULL, m_tot_parts, TRUE))
{
bitmap_free(&m_bulk_insert_started);
DBUG_RETURN(1); DBUG_RETURN(1);
}
bitmap_set_all(&(m_part_info->used_partitions)); bitmap_set_all(&(m_part_info->used_partitions));
} }
...@@ -2552,12 +2560,18 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) ...@@ -2552,12 +2560,18 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
calling open on all individual handlers. calling open on all individual handlers.
*/ */
m_handler_status= handler_opened; m_handler_status= handler_opened;
if (m_part_info->part_expr)
m_part_func_monotonicity_info=
m_part_info->part_expr->get_monotonicity_info();
else if (m_part_info->list_of_part_fields)
m_part_func_monotonicity_info= MONOTONIC_STRICT_INCREASING;
info(HA_STATUS_VARIABLE | HA_STATUS_CONST); info(HA_STATUS_VARIABLE | HA_STATUS_CONST);
DBUG_RETURN(0); DBUG_RETURN(0);
err_handler: err_handler:
while (file-- != m_file) while (file-- != m_file)
(*file)->close(); (*file)->close();
bitmap_free(&m_bulk_insert_started);
if (!is_clone) if (!is_clone)
bitmap_free(&(m_part_info->used_partitions)); bitmap_free(&(m_part_info->used_partitions));
...@@ -2605,6 +2619,7 @@ int ha_partition::close(void) ...@@ -2605,6 +2619,7 @@ int ha_partition::close(void)
DBUG_ASSERT(table->s == table_share); DBUG_ASSERT(table->s == table_share);
delete_queue(&m_queue); delete_queue(&m_queue);
bitmap_free(&m_bulk_insert_started);
if (!is_clone) if (!is_clone)
bitmap_free(&(m_part_info->used_partitions)); bitmap_free(&(m_part_info->used_partitions));
file= m_file; file= m_file;
...@@ -3021,6 +3036,8 @@ int ha_partition::write_row(uchar * buf) ...@@ -3021,6 +3036,8 @@ int ha_partition::write_row(uchar * buf)
} }
m_last_part= part_id; m_last_part= part_id;
DBUG_PRINT("info", ("Insert in partition %d", part_id)); DBUG_PRINT("info", ("Insert in partition %d", part_id));
start_part_bulk_insert(part_id);
tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */ tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */
error= m_file[part_id]->ha_write_row(buf); error= m_file[part_id]->ha_write_row(buf);
if (have_auto_increment && !table->s->next_number_keypart) if (have_auto_increment && !table->s->next_number_keypart)
...@@ -3083,6 +3100,7 @@ int ha_partition::update_row(const uchar *old_data, uchar *new_data) ...@@ -3083,6 +3100,7 @@ int ha_partition::update_row(const uchar *old_data, uchar *new_data)
} }
m_last_part= new_part_id; m_last_part= new_part_id;
start_part_bulk_insert(new_part_id);
if (new_part_id == old_part_id) if (new_part_id == old_part_id)
{ {
DBUG_PRINT("info", ("Update in partition %d", new_part_id)); DBUG_PRINT("info", ("Update in partition %d", new_part_id));
...@@ -3247,22 +3265,65 @@ int ha_partition::delete_all_rows() ...@@ -3247,22 +3265,65 @@ int ha_partition::delete_all_rows()
DESCRIPTION DESCRIPTION
rows == 0 means we will probably insert many rows rows == 0 means we will probably insert many rows
*/ */
void ha_partition::start_bulk_insert(ha_rows rows) void ha_partition::start_bulk_insert(ha_rows rows)
{ {
handler **file;
DBUG_ENTER("ha_partition::start_bulk_insert"); DBUG_ENTER("ha_partition::start_bulk_insert");
rows= rows ? rows/m_tot_parts + 1 : 0; m_bulk_inserted_rows= 0;
file= m_file; bitmap_clear_all(&m_bulk_insert_started);
do /* use the last bit for marking if bulk_insert_started was called */
{ bitmap_set_bit(&m_bulk_insert_started, m_tot_parts);
(*file)->ha_start_bulk_insert(rows);
} while (*(++file));
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
/*
Check if start_bulk_insert has been called for this partition,
if not, call it and mark it called
*/
void ha_partition::start_part_bulk_insert(uint part_id)
{
if (!bitmap_is_set(&m_bulk_insert_started, part_id) &&
bitmap_is_set(&m_bulk_insert_started, m_tot_parts))
{
m_file[part_id]->ha_start_bulk_insert(guess_bulk_insert_rows());
bitmap_set_bit(&m_bulk_insert_started, part_id);
}
m_bulk_inserted_rows++;
}
/*
Try to predict the number of inserts into this partition.
If less than 10 rows (including 0 which means Unknown)
just give that as a guess
If monotonic partitioning function was used
guess that 50 % of the inserts goes to the first partition
For all other cases, guess on equal distribution between the partitions
*/
ha_rows ha_partition::guess_bulk_insert_rows()
{
DBUG_ENTER("guess_bulk_insert_rows");
if (estimation_rows_to_insert < 10)
DBUG_RETURN(estimation_rows_to_insert);
/* If first insert/partition and monotonic partition function, guess 50%. */
if (!m_bulk_inserted_rows &&
m_part_func_monotonicity_info != NON_MONOTONIC &&
m_tot_parts > 1)
DBUG_RETURN(estimation_rows_to_insert / 2);
/* Else guess on equal distribution (+1 is to avoid returning 0/Unknown) */
if (m_bulk_inserted_rows < estimation_rows_to_insert)
DBUG_RETURN(((estimation_rows_to_insert - m_bulk_inserted_rows)
/ m_tot_parts) + 1);
/* The estimation was wrong, must say 'Unknown' */
DBUG_RETURN(0);
}
/* /*
Finish a large batch of insert rows Finish a large batch of insert rows
...@@ -3272,21 +3333,29 @@ void ha_partition::start_bulk_insert(ha_rows rows) ...@@ -3272,21 +3333,29 @@ void ha_partition::start_bulk_insert(ha_rows rows)
RETURN VALUE RETURN VALUE
>0 Error code >0 Error code
0 Success 0 Success
Note: end_bulk_insert can be called without start_bulk_insert
being called, see bug¤44108.
*/ */
int ha_partition::end_bulk_insert() int ha_partition::end_bulk_insert()
{ {
int error= 0; int error= 0;
handler **file; uint i;
DBUG_ENTER("ha_partition::end_bulk_insert"); DBUG_ENTER("ha_partition::end_bulk_insert");
file= m_file; if (!bitmap_is_set(&m_bulk_insert_started, m_tot_parts))
do DBUG_RETURN(error);
for (i= 0; i < m_tot_parts; i++)
{ {
int tmp; int tmp;
if ((tmp= (*file)->ha_end_bulk_insert())) if (bitmap_is_set(&m_bulk_insert_started, i) &&
(tmp= m_file[i]->ha_end_bulk_insert()))
error= tmp; error= tmp;
} while (*(++file)); }
bitmap_clear_all(&m_bulk_insert_started);
DBUG_RETURN(error); DBUG_RETURN(error);
} }
......
...@@ -176,6 +176,11 @@ class ha_partition :public handler ...@@ -176,6 +176,11 @@ class ha_partition :public handler
This to ensure it will work with statement based replication. This to ensure it will work with statement based replication.
*/ */
bool auto_increment_safe_stmt_log_lock; bool auto_increment_safe_stmt_log_lock;
/** For optimizing ha_start_bulk_insert calls */
MY_BITMAP m_bulk_insert_started;
ha_rows m_bulk_inserted_rows;
/** used for prediction of start_bulk_insert rows */
enum_monotonicity_info m_part_func_monotonicity_info;
public: public:
handler *clone(MEM_ROOT *mem_root); handler *clone(MEM_ROOT *mem_root);
virtual void set_part_info(partition_info *part_info) virtual void set_part_info(partition_info *part_info)
...@@ -353,7 +358,6 @@ class ha_partition :public handler ...@@ -353,7 +358,6 @@ class ha_partition :public handler
Bulk inserts are supported if all underlying handlers support it. Bulk inserts are supported if all underlying handlers support it.
start_bulk_insert and end_bulk_insert is called before and after a start_bulk_insert and end_bulk_insert is called before and after a
number of calls to write_row. number of calls to write_row.
Not yet though.
*/ */
virtual int write_row(uchar * buf); virtual int write_row(uchar * buf);
virtual int update_row(const uchar * old_data, uchar * new_data); virtual int update_row(const uchar * old_data, uchar * new_data);
...@@ -361,6 +365,10 @@ class ha_partition :public handler ...@@ -361,6 +365,10 @@ class ha_partition :public handler
virtual int delete_all_rows(void); virtual int delete_all_rows(void);
virtual void start_bulk_insert(ha_rows rows); virtual void start_bulk_insert(ha_rows rows);
virtual int end_bulk_insert(); virtual int end_bulk_insert();
private:
ha_rows guess_bulk_insert_rows();
void start_part_bulk_insert(uint part_id);
public:
virtual bool is_fatal_error(int error, uint flags) virtual bool is_fatal_error(int error, uint flags)
{ {
......
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