MySQL的写入数据存储过程

来源:这里教程网 时间:2026-03-01 16:44:58 作者:

insert 写入数据ha_innobase::write_row方法写入数据, write_row方法中进行自增列的锁定更新 构建映射的template,然后通过innodb_srv_conc_enter_innodb进入innodb,这里会判断是否会超过innodb的并发限制

innodb_srv_conc_enter_innodb(
/*=========================*/
trx_t*  trx)    /* in: transaction handle */
{
if (UNIV_LIKELY(srv_thread_concurrency >= SRV_CONCURRENCY_THRESHOLD)) {
return;
}
srv_conc_enter_innodb(trx);
}

srv_conc_enter_innodb 方法中描述了,线程是等待还是休眠 如果线程有ticket,可以直接进入,如果innodb的当前线程没有超过srv_thread_concurrency限制,可以进入,否则线程没有持有latch 的情况下,进入休眠状态SRV_THREAD_SLEEP_DELAY,然后重新尝试 ,如果持有latch 会进入队列进行排队 在进入innodb 后,执行row_insert_for_mysql进行数据的写入,这个方法就是innodb 提供的对外接口。函数传入的记录是mysql的格式, 函数中先进行row_mysql_delay_if_needed的判断,如果purge有滞后,会延迟dml的操作,进入srv_dml_needed_delay指定的时间休眠。 然后开始事务,继续调用row_mysql_convert_row_to_innobase 进行格式的转换,将mysql的格式转换成innodb的格式。 针对每列,调用row_mysql_store_col_in_innobase_format进行存储 转换完成后,调用row_ins 进行写入,在row_ins中进行row_id 分配,获取到table的cluster index后,调用row_ins_index_entry_step 进行插入,row_ins_index_entry_set_vals 在插入完cluster index后,dict_table_get_next_index 查找下一个index,写入二级索引 写入结束

row_ins_index_entry_step(que_thr_t * thr, ins_node_t * node) (/root/mysql-5.0.15/innobase/row/row0ins.c:2214)
row_ins(ins_node_t * node, que_thr_t * thr) (/root/mysql-5.0.15/innobase/row/row0ins.c:2346)
row_ins_step(que_thr_t * thr) (/root/mysql-5.0.15/innobase/row/row0ins.c:2450)
row_insert_for_mysql(unsigned char * mysql_rec, row_prebuilt_t * prebuilt) (/root/mysql-5.0.15/innobase/row/row0mysql.c:1141)
ha_innobase::write_row(ha_innobase * const this, mysql_byte * record) (/root/mysql-5.0.15/sql/ha_innodb.cc:3371)
write_record(THD * thd, TABLE * table, COPY_INFO * info) (/root/mysql-5.0.15/sql/sql_insert.cc:1146)
mysql_insert(THD * thd, TABLE_LIST * table_list, List<Item> & fields, List<List<Item> > & values_list, List<Item> & update_fields, List<Item> & update_values, enum_duplicates duplic, bool ignore) (/root/mysql-5.0.15/sql/sql_insert.cc:531)
mysql_execute_command(THD * thd) (/root/mysql-5.0.15/sql/sql_parse.cc:3239)
mysql_parse(THD * thd, char * inBuf, uint length) (/root/mysql-5.0.15/sql/sql_parse.cc:5536)
dispatch_command(enum_server_command command, THD * thd, char * packet, unsigned int packet_length) (/root/mysql-5.0.15/sql/sql_parse.cc:1697)
do_command(THD * thd) (/root/mysql-5.0.15/sql/sql_parse.cc:1498)
handle_one_connection(void * arg) (/root/mysql-5.0.15/sql/sql_parse.cc:1143)
libpthread.so.0!start_thread (Unknown Source:0)
libc.so.6!clone (Unknown Source:0)

从这个过程中,我们可以看到mysql的写入跟事务系统是完全解耦合的,事务系统的调用就是调用开始事务的方法, 写入后,然后开始写入binlog,然后开始进入提交阶段,进行两阶段提交,两阶段提交的过程另外blog有记录。 关于purge导致的dml delay,查看trx_purge函数,该函数控制delay多久

/* Close and free the old purge view */    
read_view_close(purge_sys->view);
purge_sys->view = NULL;
mem_heap_empty(purge_sys->heap);
/* Determine how much data manipulation language (DML) statements
    need to be delayed in order to reduce the lagging of the purge
    thread. */
srv_dml_needed_delay = 0; /* in microseconds; default: no delay */
/* If we cannot advance the 'purge view' because of an old
    'consistent read view', then the DML statements cannot be delayed.
    Also, srv_max_purge_lag <= 0 means 'infinity'. */
if (srv_max_purge_lag > 0
&& !UT_LIST_GET_LAST(trx_sys->view_list)) {
float   ratio = (float) trx_sys->rseg_history_len
/ srv_max_purge_lag;
if (ratio > ULINT_MAX / 10000) {
/* Avoid overflow: maximum delay is 4295 seconds */
srv_dml_needed_delay = ULINT_MAX;
} else if (ratio > 1) {
/* If the history list length exceeds the
            innodb_max_purge_lag, the
            data manipulation statements are delayed
            by at least 5000 microseconds. */
srv_dml_needed_delay = (ulint) ((ratio - .5) * 10000);
}
}
purge_sys->view = read_view_oldest_copy_or_open_new(NULL,
purge_sys->heap);
mutex_exit(&kernel_mutex);
rw_lock_x_unlock(&(purge_sys->latch));
purge_sys->state = TRX_PURGE_ON;
/* Handle at most 20 undo log pages in one purge batch */
一次最多20个undo log page
purge_sys->handle_limit = purge_sys->n_pages_handled + 20;
old_pages_handled = purge_sys->n_pages_handled;
mutex_exit(&(purge_sys->mutex));
mutex_enter(&kernel_mutex);
thr = que_fork_start_command(purge_sys->query);
ut_ad(thr);
/*  thr2 = que_fork_start_command(purge_sys->query);
    
    ut_ad(thr2); */
mutex_exit(&kernel_mutex);
/*  srv_que_task_enqueue(thr2); */
if (srv_print_thread_releases) {
fputs("Starting purge\n", stderr);
}
que_run_threads(thr);
if (srv_print_thread_releases) {
fprintf(stderr,
"Purge ends; pages handled %lu\n",
(ulong) purge_sys->n_pages_handled);
}
return(purge_sys->n_pages_handled - old_pages_handled);

innodb_max_purge_lag 这个参数默认是0,没有延时

 有兴趣学习源码的加群一起学习啊 QQ:    700072075

相关推荐