MySQL的寫入資料儲存過程
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
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/25719946/viewspace-2899893/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- MySql資料庫——儲存過程MySql資料庫儲存過程
- mysql 儲存過程MySql儲存過程
- Mysql使用儲存過程快速新增百萬資料MySql儲存過程
- MySQL資料寫入過程介紹MySql
- Mysql 儲存過程的使用MySql儲存過程
- MySQL入門--儲存過程(PROCEDURE)和儲存函式(FUNCTION)MySql儲存過程儲存函式Function
- 資料庫儲存過程資料庫儲存過程
- [MySQL光速入門]015 聊聊儲存過程MySql儲存過程
- MySQL之儲存過程MySql儲存過程
- MySQL---------儲存過程MySql儲存過程
- mysql儲存過程整理MySql儲存過程
- MySQL-09-mysql 儲存過程入門介紹MySql儲存過程
- mysql 匯入匯出資料庫以及函式、儲存過程的介紹MySql資料庫函式儲存過程
- MySQL入門系列:儲存程式(三)之儲存過程簡介MySql儲存過程
- mysql儲存過程的引數MySql儲存過程
- 【SqlServer】清除過期資料的儲存過程SQLServer儲存過程
- mysql中使用儲存過程生成1億條資料MySql儲存過程
- mysql如何呼叫儲存過程MySql儲存過程
- mysql和orcale的儲存過程和儲存函式MySql儲存過程儲存函式
- Mysql 5.7儲存過程的學習MySql儲存過程
- MySQL儲存過程的建立和使用MySql儲存過程
- 【資料庫】資料庫儲存過程(一)資料庫儲存過程
- oracle儲存過程書寫格式Oracle儲存過程
- MySQL儲存過程 (即函式)MySql儲存過程函式
- mySql 儲存過程與函式MySql儲存過程函式
- Laravel 中使用 MySQL 儲存過程LaravelMySql儲存過程
- MySQL 儲存過程和函式MySql儲存過程函式
- MySQL儲存過程和函式MySql儲存過程函式
- mysql多次呼叫儲存過程的問題MySql儲存過程
- 恢復MySQL資料庫建立儲存過程是遇到錯誤MySql資料庫儲存過程
- 儲存過程_造使用者資料儲存過程
- [MySQL光速入門]017 儲存過程中的"異常處理"MySql儲存過程
- MySQL儲存過程語句及呼叫MySql儲存過程
- MySQL儲存過程中如何使用ROLLBACKMySql儲存過程
- MySQL--儲存過程與檢視MySql儲存過程
- mysql 儲存過程 procedure 批次建表MySql儲存過程
- MySQL的物理儲存結構和session過程MySqlSession
- MySQL儲存過程的許可權問題MySql儲存過程