1.首先客戶端通過tcp/ip發送一條sql語句到server層的SQL interface
2.SQL interface接到該請求后,先對該條語句進行解析,驗證權限是否匹配
3.驗證通過以后,分析器會對該語句分析,是否語法有錯誤等
4.接下來是優化器器生成相應的執行計划,選擇最優的執行計划
5.之后會是執行器根據執行計划執行這條語句。在這一步會去open table,如果該table上有MDL,則等待。
如果沒有,則加在該表上加短暫的MDL(S)
(如果opend_table太大,表明open_table_cache太小。需要不停的去打開frm文件)
6.進入到引擎層,首先會去innodb_buffer_pool里的data dictionary(元數據信息)得到表信息
7.通過元數據信息,去lock info里查出是否會有相關的鎖信息,並把這條update語句需要的
鎖信息寫入到lock info里(鎖這里還有待補充)
8.然后涉及到的老數據通過快照的方式存儲到innodb_buffer_pool里的undo page里,並且記錄undo log修改的redo
(如果data page里有就直接載入到undo page里,如果沒有,則需要去磁盤里取出相應page的數據,載入到undo page里)
9.在innodb_buffer_pool的data page做update操作。並把操作的物理數據頁修改記錄到redo log buffer里
由於update這個事務會涉及到多個頁面的修改,所以redo log buffer里會記錄多條頁面的修改信息。
因為group commit的原因,這次事務所產生的redo log buffer可能會跟隨其它事務一同flush並且sync到磁盤上
10.同時修改的信息,會按照event的格式,記錄到binlog_cache中。(這里注意binlog_cache_size是transaction級別的,不是session級別的參數,
一旦commit之后,dump線程會從binlog_cache里把event主動發送給slave的I/O線程)
11.之后把這條sql,需要在二級索引上做的修改,寫入到change buffer page,等到下次有其他sql需要讀取該二級索引時,再去與二級索引做merge
(隨機I/O變為順序I/O,但是由於現在的磁盤都是SSD,所以對於尋址來說,隨機I/O和順序I/O差距不大)
12.此時update語句已經完成,需要commit或者rollback。這里討論commit的情況,並且雙1
13.commit操作,由於存儲引擎層與server層之間采用的是內部XA(保證兩個事務的一致性,這里主要保證redo log和binlog的原子性),
所以提交分為prepare階段與commit階段
14.prepare階段,將事務的xid寫入,將binlog_cache里的進行flush以及sync操作(大事務的話這步非常耗時)
15.commit階段,由於之前該事務產生的redo log已經sync到磁盤了。所以這步只是在redo log里標記commit
16.當binlog和redo log都已經落盤以后,如果觸發了刷新臟頁的操作,先把該臟頁復制到doublewrite buffer里,把doublewrite buffer里的刷新到共享表空間,然后才是通過page cleaner線程把臟頁寫入到磁盤中