源碼淺析:InnoDB彙集索引如何定位到數據的物理位置,並從磁盤讀取

索引結構概述:html

MyISAM索引文件和數據文件是分離的,索引文件僅保存數據記錄的地址。這與Oracle的索引結構類似,比較好理解。那麼,經常使用的Innodb彙集索引結構是怎樣的呢?node

InnoDB的數據文件自己(.ibd文件)就是索引文件。在InnoDB中,表數據文件自己就是按B+Tree組織的一個索引結構,這棵樹的葉節點data域保存了完整的數據記錄。這個索引的key是數據表的主鍵,所以InnoDB表數據文件自己就是主索引。mysql

上圖是InnoDB主索引(同時也是數據文件)的示意圖,能夠看到葉節點包含了完整的數據記錄。這種索引叫作彙集索引。由於InnoDB的數據文件自己要按主鍵彙集,因此InnoDB要求表必須有主鍵(MyISAM能夠沒有),若是沒有顯式指定,則MySQL系統會自動選擇一個能夠惟一標識數據記錄的列做爲主鍵,若是不存在這種列,則MySQL自動爲InnoDB表生成一個隱含字段做爲主鍵,這個字段長度爲6個字節,類型爲長整形。sql

 

索引數據結構:數據結構

可能上面的描述還不夠直觀,我又翻閱了《MySQL技術內幕:Innodb存儲引擎》一書,在其第172頁找到了以下圖片。ide

 

 

 

 

 

從磁盤讀取:函數

能夠看出,彙集索引非葉子節點中,Pointer(索引鍵值)指向的是ibd文件的Page Offset(File Header中的FIL_PAGE_OFFSET),這樣就定位到數據塊在ibd文件中的偏移量了。spa

接下來,首先肯定該塊是否在Innodb buffer pool中,我在這裏僅分析不在Innodb buffer pool的狀況:操作系統

 每一個page的頭部,有Fil Header,從Fil Header中的FIL_PAGE_SPACE能夠知道space id,而後經過一系列的函數調用,找到數據塊,將它讀入Innodb buffer pool,而後經過Page Directory(頁目錄)進行二分查找,來定位到行記錄,這個過程當中須要使用Record Header中的next_record。code

 

函數調用過程:

本案例(基於MySQL5.7.12)中重點的函數調用過程以下圖:

 1      mysqld.exe!SyncFileIO::execute(const IORequest & request) 行 4000   //以後,會經過SyncFileIO::execute去調用操做系統的ReadFile SYSTEM CALL,真正地從文件系統中讀取數據塊
 	mysqld.exe!os_file_io(const IORequest & in_type, void * file, void * buf, unsigned __int64 n, unsigned __int64 offset, dberr_t * err) 行 5388
 	mysqld.exe!os_file_pread(IORequest & type, void * file, void * buf, unsigned __int64 n, unsigned __int64 offset, dberr_t * err) 行 5566
 	mysqld.exe!os_file_read_page(IORequest & type, void * file, void * buf, unsigned __int64 offset, unsigned __int64 n, unsigned __int64 * o, bool exit_on_err) 行 5605
 	mysqld.exe!os_file_read_func(IORequest & type, void * file, void * buf, unsigned __int64 offset, unsigned __int64 n) 行 5999
 	mysqld.exe!fil_node_open_file(fil_node_t * node) 行 760
 	mysqld.exe!fil_node_prepare_for_io(fil_node_t * node, fil_system_t * system, fil_space_t * space) 行 5305
 	mysqld.exe!fil_space_get_space(unsigned __int64 id) 行 1497
 	mysqld.exe!fil_space_get_flags(unsigned __int64 id) 行 1587
 	mysqld.exe!fil_space_get_page_size(unsigned __int64 id, bool * found) 行 1686
 	mysqld.exe!buf_page_get_gen(const page_id_t & page_id, const page_size_t & page_size, unsigned __int64 rw_latch, buf_block_t * guess, unsigned __int64 mode, const char * file, unsigned __int64 line, mtr_t * mtr, bool dirty_with_no_latch) 行 4076
 	mysqld.exe!btr_cur_open_at_index_side_func(bool from_left, dict_index_t * index, unsigned __int64 latch_mode, btr_cur_t * cursor, unsigned __int64 level, const char * file, unsigned __int64 line, mtr_t * mtr) 行 2255
 	mysqld.exe!btr_pcur_open_at_index_side(bool from_left, dict_index_t * index, unsigned __int64 latch_mode, btr_pcur_t * pcur, bool init_pcur, unsigned __int64 level, mtr_t * mtr) 行 564
 	mysqld.exe!row_search_get_max_rec(dict_index_t * index, mtr_t * mtr) 行 6344
 	mysqld.exe!row_search_max_autoinc(dict_index_t * index, const char * col_name, unsigned __int64 * value) 行 6383
 	mysqld.exe!ha_innobase::innobase_initialize_autoinc() 行 5694
 	mysqld.exe!ha_innobase::open(const char * name, int mode, unsigned int test_if_locked) 行 6097
 	mysqld.exe!handler::ha_open(TABLE * table_arg, const char * name, int mode, int test_if_locked) 行 2680
 	mysqld.exe!open_table_from_share(THD * thd, TABLE_SHARE * share, const char * alias, unsigned int db_stat, unsigned int prgflag, unsigned int ha_open_flags, TABLE * outparam, bool is_create_table) 行 3319
 	mysqld.exe!open_table(THD * thd, TABLE_LIST * table_list, Open_table_context * ot_ctx) 行 3521
 	mysqld.exe!open_and_process_table(THD * thd, LEX * lex, TABLE_LIST * tables, unsigned int * counter, unsigned int flags, Prelocking_strategy * prelocking_strategy, bool has_prelocking_list, Open_table_context * ot_ctx) 行 5107
 	mysqld.exe!open_tables(THD * thd, TABLE_LIST * * start, unsigned int * counter, unsigned int flags, Prelocking_strategy * prelocking_strategy) 行 5718
 	mysqld.exe!open_tables_for_query(THD * thd, TABLE_LIST * tables, unsigned int flags) 行 6485
 	mysqld.exe!execute_sqlcom_select(THD * thd, TABLE_LIST * all_tables) 行 5080
 	mysqld.exe!mysql_execute_command(THD * thd, bool first_level) 行 2758
 	mysqld.exe!mysql_parse(THD * thd, Parser_state * parser_state) 行 5519
 	mysqld.exe!dispatch_command(THD * thd, const COM_DATA * com_data, enum_server_command command) 行 1432
 	mysqld.exe!do_command(THD * thd) 行 997
 	mysqld.exe!handle_connection(void * arg) 行 301
 	mysqld.exe!pfs_spawn_thread(void * arg) 行 2190
 	mysqld.exe!win_thread_start(void * p) 行 37	
 	[外部代碼]	

 

其中幾個函數對應的源代碼文件位置以下:

buf_page_get_gen(storage/innobase/buf/buf0buf.cc)

buf_read_page(storage/innobase/buf/buf0rea.cc)

buf_read_page_low(storage/innobase/buf/buf0rea.cc)

buf_page_io_complete(storage/innobase/buf/buf0buf.cc)

ibuf_merge_or_delete_for_page(storage/innobase/buf/ibuf0ibuf.cc)

ibuf_bitmap_get_map_page_func(storage/innobase/buf/ibuf0ibuf.cc)

fil_io(storage/innobase/fil/fil0fil.cc)

fil_space_get_by_id(storage/innobase/fil/fil0fil.cc)   -- 這是經過space_id查找對應ibd文件的函數

fil_node_prepare_for_io(storage/innobase/fil/fil0fil.cc)

fil_node_open_file(storage/innobase/fil/fil0fil.cc)

os_file_read(storage/innobase/os/os0file.cc)

 

 

參考連接:

http://blog.codinglabs.org/articles/theory-of-mysql-index.html  

http://www.javashuo.com/article/p-fdwhccws-kw.html

相關文章
相關標籤/搜索