MySQL 记录、页、索引的数据结构简析( 四 )

其中:

  • ins_node_t* ins_node,该结构体很重要,下文中将介绍;
  • btr_pcur_t* pcur,持久化游标用于保存当前查询的记录;
  • mysql_row_templ_t* mysql_template,辅助结构 , 主要保存列的元数据信息,用于加快行记录格式的转换 。
 
row_prebuilt_t 结构体与 build_template 函数的作用参考 ChatGPT:
  1. row_prebuilt_t:row_prebuilt_t结构体是 InnoDB 存储引擎用来预存储有关某个表操作所需的信息的数据结构 。这个结构体包括了众多和查询执行相关的字段,如指向 InnoDB 内部诸如表描述(dict_table_t)、索引描述(dict_index_t)的指针;控制当前操作的游标状态;查询的模板信息;用于读写操作的缓冲区;锁定信息等 。简言之,row_prebuilt_t是一个操作上下文,它保存了InnoDB在执行诸如插入、更新、删除、查询等操作时所需要的所有上下文信息 。
  2. build_template:build_template函数的主要工作是为 SQL 语句的执行准备模板数据,这些数据用于确定当从存储引擎获取数据时应该返回哪些列,以及如何快速地从 InnoDB 的内部格式转换为 MySQL 格式 。例如,如果一个 SELECT 语句只查询了表中的一些列,则build_template将生成相应的模板以确保只有这些被查询的列的数据被读取和转换 。这个过程包括决定哪些列可以跳过、哪些列需要转换等 。这样就可以避免不必要的数据转换和传输,提高查询效率 。
在 InnoDB 存储引擎的设计中,row_prebuilt_t和build_template都是实现 SQL 层与存储引擎层之间高效数据交互的重要组成部分 。一方面,row_prebuilt_t作为一个操作上下文,保存了完成某个表操作所需的所有信息;另一方面,build_template则通过预先构建模板来优化数据列的读取和转换过程 。
byte -> dtuple_t* rowrow_insert_for_mysql 函数中调用 row_insert_for_mysql_using_ins_graph 函数 , 其中将 Server 层的记录格式转换为 InnoDB 的记录格式,具体是从 byte 转换为 dtuple_t 。
// storage/innobase/row/row0mysql.ccstaticdberr_trow_insert_for_mysql_using_ins_graph( const byte* mysql_rec,/* row in the MySQL format */ row_prebuilt_t* prebuilt)/* prebuilt struct in MySQL handle */{que_thr_t* thr;ins_node_t* node= prebuilt->ins_node;// 主要构造用于执行插入操作的 2 个对象: // 1. ins_node_t 对象,保存在 prebuilt->ins_node 中 // 2. que_fork_t 对象,保存在 prebuilt->ins_graph 中 row_get_prebuilt_insert_row(prebuilt); node = prebuilt->ins_node; // 把 server 层的记录格式转换为 InnoDB 的记录格式 row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec,&blob_heap);thr->run_node = node; thr->prev_node = node;// 执行插入操作,插入记录到主键索引、二级索引(包含唯一索引、非唯一索引) /*插入记录*/ row_ins_step(thr);}其中:
  • 调用 row_get_prebuilt_insert_row 函数给 m_prebuilt->ins_node 成员赋初值,如 dtuple_t;
  • 调用 row_mysql_convert_row_to_innobase 函数转换行记录格式;
  • 调用 row_ins_step 函数插入记录,其中入参 que_thr_t* thr,thr->run_node = node = prebuilt->ins_node,具体 que_thr_t 结构体暂不介绍 。
 
这里又出现了一个重要的结构体 ins_node_t , 该结构体部分成员如下所示 。
/* Insert node structure */struct ins_node_t{ dtuple_t* row; /*!< row to insert */ dict_table_t* table; /*!< table where to insert */ sel_node_t* select; /*!< select in searched insert */ que_node_t* values_list;/* list of expressions to evaluate andinsert in an INS_VALUES insert */ ulintstate; /*!< node execution state */ dict_index_t* index; /*!< NULL, or the next index where the indexentry should be inserted */ dtuple_t* entry; /*!< NULL, or entry to insert in the index;after a successful insert of the entry,this should be reset to NULL */}其中:
  • dtuple_t* row,其中保存完整的行数据;
  • dtuple_t* entry,给每个 index 创建一个 dtuple_t,用于保存索引中的数据 , 比如二级索引中只需要保存索引列和主键列,因此可以理解为针对特定索引优化后的列版本 。
 
row_mysql_convert_row_to_innobase 函数中遍历索引的所有列(prebuilt->n_template)进行赋值 。
staticvoidrow_mysql_convert_row_to_innobase(/*==============================*/ dtuple_t* row,/*!< in/out: Innobase row where thefield type information is alreadycopied there! */ row_prebuilt_t* prebuilt, /*!< in: prebuilt struct where templatemust be of type ROW_MYSQL_WHOLE_ROW */ const byte* mysql_rec, /*!< in: row in the MySQL format; */ mem_heap_t** blob_heap) /*!< in: FIX_ME, remove this afterserver fixes its issue */{ const mysql_row_templ_t*templ;for (i = 0; i < prebuilt->n_template; i++) {templ = prebuilt->mysql_template + i;// 获取 fielddfield = dtuple_get_nth_field(row, n_col);// 格式转换,从 rec 写入 dtuple_trow_mysql_store_col_in_innobase_format(/* dfield_t* dfield, call to set field */dfield,/* byte* buf, buffer for a converted integer value */prebuilt->ins_upd_rec_buff + templ->mysql_col_offset,/* ibool row_format_col, TRUE if the mysql_data is from a MySQL row, FALSE if from a MySQL key value; */TRUE,/* byte* mysql_data, MySQL row format data */mysql_rec + templ->mysql_col_offset,/* ulint col_len, MySQL column length */templ->mysql_col_len,/*!< ulint comp, nonzero=compact format */dict_table_is_comp(prebuilt->table));}


推荐阅读