引子

说几句题外话,在京被困三个月之久,不能回家,所以这个源码分析就中断了。之所以在家搞这个数据库的源码分析,主要是在家环境齐全,公司的电脑老旧不堪。意外事件往往打断正常的习惯和运行轨迹,但这却是正常现象。回来也有两周,从本周开始恢复这个源码分析的系列。
大德久远,有始有终!

一、索引

什么是索引?索引有什么作用?还记得上小学时,老是教使用字典么?如果一个字不认识或者知道读音但字儿不会写都可以通过拼音或者笔画直接定位到某个字,然后它的后面就是这个字的具体的页码位置。翻到这个页码,就可以看到这个字了。在这个页面上,有这个字的写法,读音以及相关的语义,甚至还有一些常用的词语的解释和造句应用举例。
两样的道理,在图书馆找一本书,也是类似的方法;在KTV点歌,也是类似的方式,只是它们随着计算机的普及,变得更简单,更容易找到。索引,原始的意思就是查找图书的一种工具。关系型数据库技术将这种工具转用过来,把它定义为“一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。”。
试想一下,在图书馆中找寻一本图书,是从第一个书架开始,一直找到所需要为止方便快捷;还是通过索引直接定位到指定的书架以及具体的位置方便快捷,这当然不言而喻。所以,在关系型数据库技术中,索引的目的很明显,就是为了查找的速度快。但需要注意的是,不一定使用索引就必定快。索引的创建、使用合理与否,决定着索引的效率。
在数据库中,一般来说,把数据库索引分成聚簇索引和非聚簇索引两大类,其它什么唯一索引,主键索引等等,都是一些特定的叫法。这个在后面的索引系列中进先分析,本篇先分析底层的相关代码。
索引虽然可以加快查找效率,但也是需要付出代价的,在计算机中无外乎两种代价,空间代价和时间代价。索引本身需要存储空间,所以空间代价一定会增大;而在数据库的数据增删改时,除了修改数据本身还要修改索引,所以时间代价也是需要付出的。

二、mysql中索引的数据结构

在MySql中,不同的存储引擎使用的不同的索引数据结构,在MyISAM(非聚族索引)和InnoDB(聚簇索引)中使用的是B+树,而在内存引擎Memory中使用是HASH。下面就重点介绍一下这两个数据结构。
这先来看一下在mysql中的索引的底层数据结构:

先看一下HASH的数据结构(storage\heap中,内存型数据库引擎):

//heapdef.h
struct HASH_INFO {HASH_INFO * next_key;uchar * ptr_to_rec;ulong hash; /* Cached key hash value. */
};
//heap.h
struct HP_KEYDEF /* Key definition with open */
{uint flag{0};       /* HA_NOSAME | HA_NULL_PART_KEY */uint keysegs{0};    /* Number of key-segment */uint length{0};     /* Length of key (automatic) */uint8 algorithm{0}; /* HASH / BTREE */HA_KEYSEG *seg{nullptr};HP_BLOCK block; /* Where keys are saved *//*Number of buckets used in hash table. Used only to provide#records estimates for heap key scans.*/ha_rows hash_buckets{0};TREE rb_tree;int (*write_key)(HP_INFO *info, HP_KEYDEF *keyinfo, const uchar *record,uchar *recpos){nullptr};int (*delete_key)(HP_INFO *info, HP_KEYDEF *keyinfo, const uchar *record,uchar *recpos, int flag){nullptr};uint (*get_key_length)(HP_KEYDEF *keydef, const uchar *key){nullptr};
};
//include/my_comare.h
struct HA_KEYSEG /* Key-portion */
{const CHARSET_INFO *charset;uint32 start;    /* Start of key in record */uint32 null_pos; /* position to NULL indicator */uint16 bit_pos;  /* Position to bit part */uint16 flag;uint16 length; /* Keylength */uint16 language;uint8 type;               /* Type of key (for sort) */uint8 null_bit;           /* bitmask to test for NULL */uint8 bit_start, bit_end; /* if bit field */uint8 bit_length;         /* Length of bit part * /
};

这个需要注意的是不要和innodb中的自适应 Hash索引(Adaptive Hash Index)混淆,它们在不同的目录中。

再看一下树的数据结构:

//storage/innobase/include/mem0mem.h
/** The info structure stored at the beginning of a heap block */
struct mem_block_info_t {uint64_t magic_n; /* magic number for debugging */
#ifdef UNIV_DEBUGchar file_name[16]; /* file name where the mem heap was created */ulint line;         /*!< line number where the mem heap was created */
#endif                /* UNIV_DEBUG */UT_LIST_BASE_NODE_T(mem_block_t)base; /* In the first block in the
the list this is the base node of the list of blocks;
in subsequent blocks this is undefined */UT_LIST_NODE_T(mem_block_t)list;             /* This contains pointers to nextand prev in the list. The first block allocatedto the heap is also the first block in this list,though it also contains the base node of the list. */ulint len;        /*!< physical length of this block in bytes */ulint total_size; /*!< physical length in bytes of all blocksin the heap. This is defined only in the basenode and is set to ULINT_UNDEFINED in others. */ulint type;       /*!< type of heap: MEM_HEAP_DYNAMIC, orMEM_HEAP_BUF possibly ORed to MEM_HEAP_BTR_SEARCH */ulint free;       /*!< offset in bytes of the first free position foruser data in the block */ulint start;      /*!< the value of the struct field 'free' at thecreation of the block */void *free_block;/* if the MEM_HEAP_BTR_SEARCH bit is set in type,and this is the heap root, this can contain anallocated buffer frame, which can be appended as afree block to the heap, if we need more space;otherwise, this is NULL */void *buf_block;/* if this block has been allocated from the bufferpool, this contains the buf_block_t handle;otherwise, this is NULL */
};/** The search info struct in an index */
struct btr_search_t {ulint ref_count; /*!< Number of blocks in this index treethat have search index builti.e. block->index points to this index.Protected by search latch exceptwhen during initialization inbtr_search_info_create(). *//** @{ The following fields are not protected by any latch.Unfortunately, this means that they must be aligned tothe machine word, i.e., they cannot be turned into bit-fields. */buf_block_t *root_guess; /*!< the root page frame when it was last timefetched, or NULL */ulint hash_analysis;     /*!< when this exceedsBTR_SEARCH_HASH_ANALYSIS, the hashanalysis starts; this is reset if nosuccess noticed */ibool last_hash_succ;    /*!< TRUE if the last search would havesucceeded, or did succeed, using the hashindex; NOTE that the value here is not exact:it is not calculated for every search, and thecalculation itself is not always accurate! */ulint n_hash_potential;/*!< number of consecutive searcheswhich would have succeeded, or did succeed,using the hash index;the range is 0 .. BTR_SEARCH_BUILD_LIMIT + 5 *//** @} *//**---------------------- @{ */ulint n_fields;  /*!< recommended prefix length for hash search:number of full fields */ulint n_bytes;   /*!< recommended prefix: number of bytes inan incomplete field@see BTR_PAGE_MAX_REC_SIZE */ibool left_side; /*!< TRUE or FALSE, depending on whetherthe leftmost record of several records withthe same prefix should be indexed in thehash index *//*---------------------- @} */
#ifdef UNIV_SEARCH_PERF_STATulint n_hash_succ; /*!< number of successful hash searches thusfar */ulint n_hash_fail; /*!< number of failed hash searches */ulint n_patt_succ; /*!< number of successful pattern searches thusfar */ulint n_searches;  /*!< number of searches */
#endif               /* UNIV_SEARCH_PERF_STAT */
#ifdef UNIV_DEBUGulint magic_n; /*!< magic number @see BTR_SEARCH_MAGIC_N */
/** value of btr_search_t::magic_n, used in assertions */
#define BTR_SEARCH_MAGIC_N 1112765
#endif /* UNIV_DEBUG */
};
//storage/innobase/include/dict0mem.h
/** Data structure for an index.  Most fields will be
initialized to 0, NULL or FALSE in dict_mem_index_create(). */
struct dict_index_t {space_index_t id;       /*!< id of the index */mem_heap_t *heap;       /*!< memory heap */id_name_t name;         /*!< index name */const char *table_name; /*!< table name */dict_table_t *table;    /*!< back pointer to table */unsigned space : 32;/*!< space where the index tree is placed */unsigned page : 32; /*!< index tree root page number */unsigned merge_threshold : 6;/*!< In the pessimistic delete, if the pagedata size drops below this limit in percent,merging it to a neighbor is tried */
#define DICT_INDEX_MERGE_THRESHOLD_DEFAULT 50unsigned type : DICT_IT_BITS;/*!< index type (DICT_CLUSTERED, DICT_UNIQUE,DICT_IBUF, DICT_CORRUPT) */
#define MAX_KEY_LENGTH_BITS 12unsigned trx_id_offset : MAX_KEY_LENGTH_BITS;/*!< position of the trx id columnin a clustered index record, if the fieldsbefore it are known to be of a fixed size,0 otherwise */
#if (1 << MAX_KEY_LENGTH_BITS) < MAX_KEY_LENGTH
#error(1<<MAX_KEY_LENGTH_BITS) < MAX_KEY_LENGTH
#endifunsigned n_user_defined_cols : 10;/*!< number of columns the user defined tobe in the index: in the internalrepresentation we add more columns */unsigned allow_duplicates : 1;/*!< if true, allow duplicate valueseven if index is created with uniqueconstraint */unsigned nulls_equal : 1;/*!< if true, SQL NULL == SQL NULL */unsigned disable_ahi : 1;/*!< if true, then disable AHI. Currentlylimited to intrinsic temporary table and SDItable as index id is not unique for such tablewhich is one of the validation criterion forahi. */unsigned n_uniq : 10;     /*!< number of fields from the beginningwhich are enough to determine an indexentry uniquely */unsigned n_def : 10;      /*!< number of fields defined so far */unsigned n_fields : 10;   /*!< number of fields in the index */unsigned n_nullable : 10; /*!< number of nullable fields */unsigned n_instant_nullable : 10;/*!< number of nullable fields before firstinstant ADD COLUMN applied to this table.This is valid only when has_instant_cols() is true */unsigned cached : 1; /*!< TRUE if the index object is in thedictionary cache */unsigned to_be_dropped : 1;/*!< TRUE if the index is to be dropped;protected by dict_operation_lock */unsigned online_status : 2;/*!< enum online_index_status.Transitions from ONLINE_INDEX_COMPLETE (toONLINE_INDEX_CREATION) are protectedby dict_operation_lock anddict_sys->mutex. Other changes areprotected by index->lock. */unsigned uncommitted : 1;/*!< a flag that is set for secondary indexesthat have not been committed to thedata dictionary yet */unsigned instant_cols : 1;/*!< TRUE if the index is clustered index and it has someinstant columns */uint32_t srid; /* spatial reference id */bool srid_is_valid;/* says whether SRID is valid - it cane beundefined */std::unique_ptr<dd::Spatial_reference_system> rtr_srs;/*!< Cached spatial reference system dictionaryentry used by R-tree indexes. */#ifdef UNIV_DEBUGuint32_t magic_n; /*!< magic number */
/** Value of dict_index_t::magic_n */
#define DICT_INDEX_MAGIC_N 76789786
#endifdict_field_t *fields; /*!< array of field descriptions */
#ifndef UNIV_HOTBACKUPst_mysql_ftparser *parser; /*!< fulltext parser plugin */bool is_ngram;/*!< true if it's ngram parser */bool has_new_v_col;/*!< whether it has a newly added virtualcolumn in ALTER */bool hidden; /*!< if the index is an hidden index */
#endif         /* !UNIV_HOTBACKUP */UT_LIST_NODE_T(dict_index_t)indexes; /*!< list of indexes of the table */btr_search_t *search_info;/*!< info used in optimistic searches */
#ifndef UNIV_HOTBACKUProw_log_t *online_log;/*!< the log of modificationsduring online index creation;valid when online_status isONLINE_INDEX_CREATION *//*----------------------*//** Statistics for query optimization *//** @{ */ib_uint64_t *stat_n_diff_key_vals;/*!< approximate number of differentkey values for this index, for eachn-column prefix where 1 <= n <=dict_get_n_unique(index) (the array isindexed from 0 to n_uniq-1); weperiodically calculate newestimates */ib_uint64_t *stat_n_sample_sizes;/*!< number of pages that were sampledto calculate each of stat_n_diff_key_vals[],e.g. stat_n_sample_sizes[3] pages were sampledto get the number stat_n_diff_key_vals[3]. */ib_uint64_t *stat_n_non_null_key_vals;/* approximate number of non-null key valuesfor this index, for each column where1 <= n <= dict_get_n_unique(index) (the arrayis indexed from 0 to n_uniq-1); Thisis used when innodb_stats_method is"nulls_ignored". */ulint stat_index_size;/*!< approximate index size indatabase pages */
#endif /* !UNIV_HOTBACKUP */ulint stat_n_leaf_pages;/*!< approximate number of leaf pages in theindex tree *//** @} */last_ops_cur_t *last_ins_cur;/*!< cache the last insert position.Currently limited to auto-generatedclustered index on intrinsic table only. */last_ops_cur_t *last_sel_cur;/*!< cache the last selected positionCurrently limited to intrinsic table only. */rec_cache_t rec_cache;/*!< cache the field that needs to bere-computed on each insert.Limited to intrinsic table as this is commonshare and can't be used without protectionif table is accessible to multiple-threads. */rtr_ssn_t rtr_ssn;           /*!< Node sequence number for RTree */rtr_info_track_t *rtr_track; /*!< tracking all R-Tree search cursors */trx_id_t trx_id;             /*!< id of the transaction that created thisindex, or 0 if the index existedwhen InnoDB was started up */zip_pad_info_t zip_pad;      /*!< Information about state ofcompression failures and successes */rw_lock_t lock;              /*!< read-write lock protecting theupper levels of the index tree */bool fill_dd;                /*!< Flag whether need to fill dd tableswhen it's a fulltext index. *//** Determine if the index has been committed to thedata dictionary.@return whether the index definition has been committed */bool is_committed() const {ut_ad(!uncommitted || !(type & DICT_CLUSTERED));return (UNIV_LIKELY(!uncommitted));}/** Flag an index committed or uncommitted.@param[in]   committed   whether the index is committed */void set_committed(bool committed) {ut_ad(!to_be_dropped);ut_ad(committed || !(type & DICT_CLUSTERED));uncommitted = !committed;}/** Get the next index.@return   next index@retval   NULL    if this was the last index */const dict_index_t *next() const {const dict_index_t *next = UT_LIST_GET_NEXT(indexes, this);ut_ad(magic_n == DICT_INDEX_MAGIC_N);return (next);}/** Get the next index.@return   next index@retval   NULL    if this was the last index */dict_index_t *next() {return (const_cast<dict_index_t *>(const_cast<const dict_index_t *>(this)->next()));}/** Check whether the index is corrupted.@return true if index is corrupted, otherwise false */bool is_corrupted() const {ut_ad(magic_n == DICT_INDEX_MAGIC_N);return (type & DICT_CORRUPT);}/* Check whether the index is the clustered index@return nonzero for clustered index, zero for other indexes */bool is_clustered() const {ut_ad(magic_n == DICT_INDEX_MAGIC_N);return (type & DICT_CLUSTERED);}/** Check whether the index is the multi-value index@return nonzero for multi-value index, zero for other indexes */bool is_multi_value() const {ut_ad(magic_n == DICT_INDEX_MAGIC_N);return (type & DICT_MULTI_VALUE);}/** Returns the minimum data size of an index record.@return minimum data size in bytes */ulint get_min_size() const {ulint size = 0;for (unsigned i = 0; i < n_fields; i++) {size += get_col(i)->get_min_size();}return (size);}/** Check whether index can be used by transaction@param[in] trx       transaction*/bool is_usable(const trx_t *trx) const;/** Check whether index has any instantly added columns@return true if this is instant affected, otherwise false */bool has_instant_cols() const { return (instant_cols); }/** Check if tuple is having instant format.@param[in] n_fields_in_tuple   number of fields in tuple@return true if yes, false otherwise. */bool is_tuple_instant_format(const uint16_t n_fields_in_tuple) const;/** Returns the number of nullable fields before specifiednth field@param[in] nth nth field to check */uint32_t get_n_nullable_before(uint32_t nth) const {uint32_t nullable = n_nullable;ut_ad(nth <= n_fields);for (uint32_t i = nth; i < n_fields; ++i) {if (get_field(i)->col->is_nullable()) {--nullable;}}return (nullable);}/** Returns the number of fields before first instant ADD COLUMN */uint32_t get_instant_fields() const;/** Adds a field definition to an index. NOTE: does not take a copyof the column name if the field is a column. The memory occupiedby the column name may be released only after publishing the index.@param[in] name_arg column name@param[in] prefix_len    0 or the column prefix length in a MySQL indexlike INDEX (textcol(25))@param[in] is_ascending   true=ASC, false=DESC */void add_field(const char *name_arg, ulint prefix_len, bool is_ascending) {dict_field_t *field;ut_ad(magic_n == DICT_INDEX_MAGIC_N);n_def++;field = get_field(n_def - 1);field->name = name_arg;field->prefix_len = (unsigned int)prefix_len;field->is_ascending = is_ascending;}/** Gets the nth field of an index.@param[in] pos   position of field@return pointer to field object */dict_field_t *get_field(ulint pos) const {ut_ad(pos < n_def);ut_ad(magic_n == DICT_INDEX_MAGIC_N);return (fields + pos);}/** Gets pointer to the nth column in an index.@param[in] pos  position of the field@return column */const dict_col_t *get_col(ulint pos) const { return (get_field(pos)->col); }/** Gets the column number the nth field in an index.@param[in] pos   position of the field@return column number */ulint get_col_no(ulint pos) const;/** Returns the position of a system column in an index.@param[in] type       DATA_ROW_ID, ...@return position, ULINT_UNDEFINED if not contained */ulint get_sys_col_pos(ulint type) const;/** Looks for column n in an index.@param[in]   n       column number@param[in] inc_prefix  true=consider column prefixes too@param[in] is_virtual  true==virtual column@return position in internal representation of the index;ULINT_UNDEFINED if not contained */ulint get_col_pos(ulint n, bool inc_prefix = false,bool is_virtual = false) const;/** Get the default value of nth field and its length if exists.If not exists, both the return value is nullptr and length is 0.@param[in]   nth nth field to get@param[in,out]  length  length of the default value@return  the default value data of nth field */const byte *get_nth_default(ulint nth, ulint *length) const {ut_ad(nth < n_fields);ut_ad(get_instant_fields() <= nth);const dict_col_t *col = get_col(nth);if (col->instant_default == nullptr) {*length = 0;return (nullptr);}*length = col->instant_default->len;ut_ad(*length == 0 || *length == UNIV_SQL_NULL ||col->instant_default->value != nullptr);return (col->instant_default->value);}/** Sets srid and srid_is_valid values@param[in] srid_value      value of SRID, may be garbageif srid_is_valid_value = false@param[in]   srid_is_valid_value value of srid_is_valid */void fill_srid_value(uint32_t srid_value, bool srid_is_valid_value) {srid_is_valid = srid_is_valid_value;srid = srid_value;}/** Check if the underlying table is compressed.@return true if compressed, false otherwise. */bool is_compressed() const;/** Check if a multi-value index is built on specified multi-valuevirtual column. Please note that there could be only one multi-valuevirtual column on the multi-value index, but not necessary the firstfield of the index.@param[in]  mv_col  multi-value virtual column@return non-zero means the column is on the index and this is thenth position of the column, zero means it's not on the index */uint32_t has_multi_value_col(const dict_v_col_t *mv_col) const {ut_ad(is_multi_value());for (uint32_t i = 0; i < n_fields; ++i) {const dict_col_t *col = get_col(i);if (mv_col->m_col.ind == col->ind) {return (i + 1);}/* Only one multi-value field, if not match then no match. */if (col->is_multi_value()) {break;}}return (0);}public:/** Get the page size of the tablespace to which this index belongs.@return the page size. */page_size_t get_page_size() const;/** Get the space id of the tablespace to which this index belongs.@return the space id. * /space_id_t space_id() const { return space; }
};

最后一个数据结构dict_index_t的注释明确说明了这就是索引结构的数据结构体,在innodb中采用的是聚集索引,聚集索引在前面提到过,索引数据和数据数据存储在同一物理空间内。

提到B+树,其实还有B树和B*树,在学习数据结构的时候儿还有AVL树和红黑树,这些在DB技术里都有应用,有兴趣的可以对比学习分析一下。其实这些树的数据结构,只要掌握了任何的其中一种,再学习其它树,只要明白它们不同和优缺点就非常容易了。

三、源码

哈希部分比较简单,这里只分析B+树的索引部分:

/** Creates an index memory object.@return own: index object */
dict_index_t *dict_mem_index_create(const char *table_name, /*!< in: table name */const char *index_name, /*!< in: index name */ulint space,            /*!< in: space where the index tree isplaced, ignored if the index is ofthe clustered type */ulint type,             /*!< in: DICT_UNIQUE,DICT_CLUSTERED, ... ORed */ulint n_fields)         /*!< in: number of fields */
{dict_index_t *index;mem_heap_t *heap;ut_ad(table_name && index_name);heap = mem_heap_create(DICT_HEAP_SIZE);index = static_cast<dict_index_t *>(mem_heap_zalloc(heap, sizeof(*index)));dict_mem_fill_index_struct(index, heap, table_name, index_name, space, type,n_fields);#ifndef UNIV_HOTBACKUP
#ifndef UNIV_LIBRARYdict_index_zip_pad_mutex_create_lazy(index);if (type & DICT_SPATIAL) {mutex_create(LATCH_ID_RTR_SSN_MUTEX, &index->rtr_ssn.mutex);index->rtr_track = static_cast<rtr_info_track_t *>(mem_heap_alloc(heap, sizeof(*index->rtr_track)));mutex_create(LATCH_ID_RTR_ACTIVE_MUTEX,&index->rtr_track->rtr_active_mutex);index->rtr_track->rtr_active = UT_NEW_NOKEY(rtr_info_active());}
#endif /* !UNIV_LIBRARY */
#endif /* !UNIV_HOTBACKUP */return (index);
}/** This function poplulates a dict_index_t index memory structure withsupplied information. */
UNIV_INLINE
void dict_mem_fill_index_struct(dict_index_t *index,    /*!< out: index to be filled */mem_heap_t *heap,       /*!< in: memory heap */const char *table_name, /*!< in: table name */const char *index_name, /*!< in: index name */ulint space,            /*!< in: space where the index tree isplaced, ignored if the index is ofthe clustered type */ulint type,             /*!< in: DICT_UNIQUE,DICT_CLUSTERED, ... ORed */ulint n_fields)         /*!< in: number of fields */
{if (heap) {index->heap = heap;index->name = mem_heap_strdup(heap, index_name);index->fields = (dict_field_t *)mem_heap_alloc(heap, 1 + n_fields * sizeof(dict_field_t));} else {index->name = index_name;index->heap = nullptr;index->fields = nullptr;}/* Assign a ulint to a 4-bit-mapped field.Only the low-order 4 bits are assigned. */index->type = type;
#ifndef UNIV_HOTBACKUPindex->space = (unsigned int)space;index->page = FIL_NULL;index->merge_threshold = DICT_INDEX_MERGE_THRESHOLD_DEFAULT;
#endif /* !UNIV_HOTBACKUP */index->table_name = table_name;index->n_fields = (unsigned int)n_fields;/* The '1 +' above prevents allocationof an empty mem block */index->allow_duplicates = false;index->nulls_equal = false;index->disable_ahi = false;index->last_ins_cur = nullptr;index->last_sel_cur = nullptr;
#ifndef UNIV_HOTBACKUPnew (&index->rec_cache) rec_cache_t();#endif /* UNIV_HOTBACKUP */
#ifdef UNIV_DEBUGindex->magic_n = DICT_INDEX_MAGIC_N;
#endif /* UNIV_DEBUG */
}/** Returns the number of fields before first instant ADD COLUMN * /
inline uint32_t dict_index_t::get_instant_fields() const {ut_ad(has_instant_cols());return (n_fields - (table->n_cols - table->n_instant_cols));
}

上面是创建索引和显示索引的信息,再看一下如何给一列增加索引:

/** Adds a column to index.
@param[in,out]  index       index
@param[in]  table       table
@param[in]  col     column
@param[in]  prefix_len  column prefix length
@param[in]  is_ascending    true=ASC, false=DESC */
void dict_index_add_col(dict_index_t *index, const dict_table_t *table,dict_col_t *col, ulint prefix_len, bool is_ascending) {dict_field_t *field;const char *col_name;#ifndef UNIV_LIBRARYif (col->is_virtual()) {
#ifndef UNIV_HOTBACKUPdict_v_col_t *v_col = reinterpret_cast<dict_v_col_t *>(col);/* When v_col->v_indexes==NULL,ha_innobase::commit_inplace_alter_table(commit=true)will evict and reload the table definition, andv_col->v_indexes will not be NULL for the new table. */if (v_col->v_indexes != nullptr) {/* Register the index with the virtual column indexlist */struct dict_v_idx_t new_idx = {index, index->n_def};v_col->v_indexes->push_back(new_idx);}col_name = dict_table_get_v_col_name_mysql(table, dict_col_get_no(col));
#else  /* !UNIV_HOTBACKUP *//* PRELIMINARY TEMPORARY WORKAROUND: is this ever used? */bool not_hotbackup = false;ut_a(not_hotbackup);
#endif /* !UNIV_HOTBACKUP */} else
#endif /* !UNIV_LIBRARY */{col_name = table->get_col_name(dict_col_get_no(col));}index->add_field(col_name, prefix_len, is_ascending);field = index->get_field(index->n_def - 1);field->col = col;/* DATA_POINT is a special type, whose fixed_len should be:1) DATA_MBR_LEN, when it's indexed in R-TREE. In this case,it must be the first col to be added.2) DATA_POINT_LEN(be equal to fixed size of column), when it'sindexed in B-TREE,3) DATA_POINT_LEN, if a POINT col is the PRIMARY KEY, and we areadding the PK col to other B-TREE/R-TREE. *//* TODO: We suppose the dimension is 2 now. */if (dict_index_is_spatial(index) && DATA_POINT_MTYPE(col->mtype) &&index->n_def == 1) {field->fixed_len = DATA_MBR_LEN;} else {field->fixed_len = static_cast<unsigned int>(col->get_fixed_size(dict_table_is_comp(table)));}if (prefix_len && field->fixed_len > prefix_len) {field->fixed_len = (unsigned int)prefix_len;}/* Long fixed-length fields that need external storage are treated asvariable-length fields, so that the extern flag can be embedded inthe length word. */if (field->fixed_len > DICT_MAX_FIXED_COL_LEN) {field->fixed_len = 0;}
#if DICT_MAX_FIXED_COL_LEN != 768/* The comparison limit above must be constant.  If it werechanged, the disk format of some fixed-length columns wouldchange, which would be a disaster. * /
#error "DICT_MAX_FIXED_COL_LEN != 768"
#endifif (!(col->prtype & DATA_NOT_NULL)) {index->n_nullable++;}
}

加载一个索引集:

/** Loads definitions for table indexes. Adds them to the data dictionarycache.@return DB_SUCCESS if ok, DB_CORRUPTION if corruption of dictionarytable or DB_UNSUPPORTED if table has unknown index type */
static dberr_t dict_load_indexes(dict_table_t *table, /*!< in/out: table */mem_heap_t *heap,    /*!< in: memory heap for temporary storage */dict_err_ignore_t ignore_err)
/*!< in: error to be ignored when
loading the index definition */
{dict_table_t *sys_indexes;dict_index_t *sys_index;btr_pcur_t pcur;dtuple_t *tuple;dfield_t *dfield;const rec_t *rec;byte *buf;mtr_t mtr;dberr_t error = DB_SUCCESS;ut_ad(mutex_own(&dict_sys->mutex));mtr_start(&mtr);sys_indexes = dict_table_get_low("SYS_INDEXES");sys_index = UT_LIST_GET_FIRST(sys_indexes->indexes);ut_ad(!dict_table_is_comp(sys_indexes));ut_ad(name_of_col_is(sys_indexes, sys_index, DICT_FLD__SYS_INDEXES__NAME,"NAME"));ut_ad(name_of_col_is(sys_indexes, sys_index, DICT_FLD__SYS_INDEXES__PAGE_NO,"PAGE_NO"));tuple = dtuple_create(heap, 1);dfield = dtuple_get_nth_field(tuple, 0);buf = static_cast<byte *>(mem_heap_alloc(heap, 8));mach_write_to_8(buf, table->id);dfield_set_data(dfield, buf, 8);dict_index_copy_types(tuple, sys_index, 1);btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, BTR_SEARCH_LEAF,&pcur, &mtr);for (;;) {dict_index_t *index = nullptr;const char *err_msg;if (!btr_pcur_is_on_user_rec(&pcur)) {/* We should allow the table to open evenwithout index when DICT_ERR_IGNORE_CORRUPT is set.DICT_ERR_IGNORE_CORRUPT is currently only setfor drop table */if (table->first_index() == nullptr &&!(ignore_err & DICT_ERR_IGNORE_CORRUPT)) {ib::warn(ER_IB_MSG_197) << "Cannot load table " << table->name<< " because it has no indexes in"" InnoDB internal data dictionary.";error = DB_CORRUPTION;goto func_exit;}break;}rec = btr_pcur_get_rec(&pcur);if ((ignore_err & DICT_ERR_IGNORE_RECOVER_LOCK) &&(rec_get_n_fields_old_raw(rec) == DICT_NUM_FIELDS__SYS_INDEXES/* a record for older SYS_INDEXES table(missing merge_threshold column) is acceptable. */||rec_get_n_fields_old_raw(rec) == DICT_NUM_FIELDS__SYS_INDEXES - 1)) {const byte *field;ulint len;field = rec_get_nth_field_old(rec, DICT_FLD__SYS_INDEXES__NAME, &len);if (len != UNIV_SQL_NULL &&static_cast<char>(*field) ==static_cast<char>(*TEMP_INDEX_PREFIX_STR)) {/* Skip indexes whose name starts withTEMP_INDEX_PREFIX, because they willbe dropped during crash recovery. */goto next_rec;}}err_msg =dict_load_index_low(buf, table->name.m_name, heap, rec, TRUE, &index);ut_ad((index == nullptr && err_msg != nullptr) ||(index != nullptr && err_msg == nullptr));if (err_msg == dict_load_index_id_err) {/* TABLE_ID mismatch means that we haverun out of index definitions for the table. */if (table->first_index() == nullptr &&!(ignore_err & DICT_ERR_IGNORE_CORRUPT)) {ib::warn(ER_IB_MSG_198)<< "Failed to load the"" clustered index for table "<< table->name << " because of the following error: " << err_msg<< "."" Refusing to load the rest of the"" indexes (if any) and the whole table"" altogether.";error = DB_CORRUPTION;goto func_exit;}break;} else if (err_msg == dict_load_index_del) {/* Skip delete-marked records. */goto next_rec;} else if (err_msg) {ib::error(ER_IB_MSG_199) << err_msg;if (ignore_err & DICT_ERR_IGNORE_CORRUPT) {goto next_rec;}error = DB_CORRUPTION;goto func_exit;}ut_ad(index);/* Check whether the index is corrupted */if (index->is_corrupted()) {ib::error(ER_IB_MSG_200) << "Index " << index->name << " of table "<< table->name << " is corrupted";if (!srv_load_corrupted && !(ignore_err & DICT_ERR_IGNORE_CORRUPT) &&index->is_clustered()) {dict_mem_index_free(index);error = DB_INDEX_CORRUPT;goto func_exit;} else {/* We will load the index if1) srv_load_corrupted is TRUE2) ignore_err is set withDICT_ERR_IGNORE_CORRUPT3) if the index corrupted is a secondaryindex */ib::info(ER_IB_MSG_201) << "Load corrupted index " << index->name<< " of table " << table->name;}}if (index->type & DICT_FTS && !dict_table_has_fts_index(table)) {/* This should have been created by now. */ut_a(table->fts != nullptr);DICT_TF2_FLAG_SET(table, DICT_TF2_FTS);}/* We check for unsupported types first, so that thesubsequent checks are relevant for the supported types. */if (index->type & ~(DICT_CLUSTERED | DICT_UNIQUE | DICT_CORRUPT | DICT_FTS |DICT_SPATIAL | DICT_VIRTUAL)) {ib::error(ER_IB_MSG_202) << "Unknown type " << index->type << " of index "<< index->name << " of table " << table->name;error = DB_UNSUPPORTED;dict_mem_index_free(index);goto func_exit;} else if (!index->is_clustered() && nullptr == table->first_index()) {ib::error(ER_IB_MSG_203)<< "Trying to load index " << index->name << " for table "<< table->name << ", but the first index is not clustered!";dict_mem_index_free(index);error = DB_CORRUPTION;goto func_exit;} else if (dict_is_old_sys_table(table->id) &&(index->is_clustered() || ((table == dict_sys->sys_tables) &&!strcmp("ID_IND", index->name)))) {/* The index was created in memory already at bootingof the database server */dict_mem_index_free(index);} else {dict_load_fields(index, heap);mutex_exit(&dict_sys->mutex);error = dict_index_add_to_cache(table, index, index->page, FALSE);mutex_enter(&dict_sys->mutex);/* The data dictionary tables should never containinvalid index definitions. */if (UNIV_UNLIKELY(error != DB_SUCCESS)) {goto func_exit;}}next_rec:btr_pcur_move_to_next_user_rec(&pcur, &mtr);}ut_ad(table->fts_doc_id_index == nullptr);if (table->fts != nullptr) {table->fts_doc_id_index =dict_table_get_index_on_name(table, FTS_DOC_ID_INDEX_NAME);}/* If the table contains FTS indexes, populate table->fts->indexes */if (dict_table_has_fts_index(table)) {ut_ad(table->fts_doc_id_index != nullptr);/* table->fts->indexes should have been created. * /ut_a(table->fts->indexes != nullptr);dict_table_get_all_fts_indexes(table, table->fts->indexes);}func_exit:btr_pcur_close(&pcur);mtr_commit(&mtr);return (error);
}

再看一看通过索引查询相关数据:

/** Gets the column number.@return col->ind, table column position (starting from 0) */
UNIV_INLINE
ulint dict_col_get_no(const dict_col_t *col) /*!< in: column */
{ut_ad(col);return (col->ind);
}/** Gets the column position in the clustered index. */
UNIV_INLINE
ulint dict_col_get_clust_pos(const dict_col_t *col,           /*!< in: table column */const dict_index_t *clust_index) /*!< in: clustered index */
{ulint i;ut_ad(col);ut_ad(clust_index);ut_ad(clust_index->is_clustered());for (i = 0; i < clust_index->n_def; i++) {const dict_field_t *field = &clust_index->fields[i];if (!field->prefix_len && field->col == col) {return (i);}}return (ULINT_UNDEFINED);
}/** Gets the column position in the given index.
@param[in]  col table column
@param[in]  index   index to be searched for column
@return position of column in the given index. */
UNIV_INLINE
ulint dict_col_get_index_pos(const dict_col_t *col, const dict_index_t *index) {ulint i;for (i = 0; i < index->n_def; i++) {const dict_field_t *field = &index->fields[i];if (!field->prefix_len && field->col == col) {return (i);}}return (ULINT_UNDEFINED);
}/** Check whether the index consists of descending columns only.
@param[in]  index  index tree
@retval true if index has any descending column
@retval false if index has only ascending columns */
UNIV_INLINE
bool dict_index_has_desc(const dict_index_t *index) {ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);for (ulint i = 0; i < index->n_def; i++) {const dict_field_t *field = &index->fields[i];if (!field->is_ascending) {return (true);}}return (false);
}/** Check if index is auto-generated clustered index.
@param[in]  index   index@return true if index is auto-generated clustered index. */
UNIV_INLINE
bool dict_index_is_auto_gen_clust(const dict_index_t *index) {return (index->type == DICT_CLUSTERED);
}/** Check whether the index is unique.@return nonzero for unique index, zero for other indexes */
UNIV_INLINE
ulint dict_index_is_unique(const dict_index_t *index) /*!< in: index */
{ut_ad(index);ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);return (index->type & DICT_UNIQUE);
}/** Check whether the index is a Spatial Index.@return  nonzero for Spatial Index, zero for other indexes */
UNIV_INLINE
ulint dict_index_is_spatial(const dict_index_t *index) /*!< in: index */
{ut_ad(index);ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);return (index->type & DICT_SPATIAL);
}/** Check whether the index contains a virtual column
@param[in]  index   index
@return nonzero for the index has virtual column, zero for other indexes */
UNIV_INLINE
ulint dict_index_has_virtual(const dict_index_t *index) {ut_ad(index);ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);return (index->type & DICT_VIRTUAL);
}/** Check whether the index is the insert buffer tree.@return nonzero for insert buffer, zero for other indexes */
UNIV_INLINE
ulint dict_index_is_ibuf(const dict_index_t *index) /*!< in: index */
{ut_ad(index);ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);return (index->type & DICT_IBUF);
}/** Check whether the index is a secondary index or the insert buffer tree.@return nonzero for insert buffer, zero for other indexes */
UNIV_INLINE
ulint dict_index_is_sec_or_ibuf(const dict_index_t *index) /*!< in: index */
{ulint type;ut_ad(index);ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);type = index->type;return (!(type & DICT_CLUSTERED) || (type & DICT_IBUF));
}

再看一下Page分裂时如何处理:


/** Splits an index page to halves and inserts the tuple. It is assumedthat mtr holds an x-latch to the index tree. NOTE: the tree x-latch isreleased within this function! NOTE that the operation of thisfunction must always succeed, we cannot reverse it: therefore enoughfree disk space (2 pages) must be guaranteed to be available beforethis function is called.@return inserted record */
rec_t *btr_page_split_and_insert(uint32_t flags,        /*!< in: undo logging and locking flags */btr_cur_t *cursor,     /*!< in: cursor at which to insert; when thefunction returns, the cursor is positionedon the predecessor of the inserted record */ulint **offsets,       /*!< out: offsets on inserted record */mem_heap_t **heap,     /*!< in/out: pointer to memory heap, or NULL */const dtuple_t *tuple, /*!< in: tuple to insert */mtr_t *mtr)            /*!< in: mtr */
{buf_block_t *block;page_t *page;page_zip_des_t *page_zip;page_no_t page_no;byte direction;page_no_t hint_page_no;buf_block_t *new_block;page_t *new_page;page_zip_des_t *new_page_zip;rec_t *split_rec;buf_block_t *left_block;buf_block_t *right_block;buf_block_t *insert_block;page_cur_t *page_cursor;rec_t *first_rec;byte *buf = nullptr; /* remove warning */rec_t *move_limit;ibool insert_will_fit;ibool insert_left;ulint n_iterations = 0;rec_t *rec;ulint n_uniq;dict_index_t *index;index = btr_cur_get_index(cursor);if (dict_index_is_spatial(index)) {/* Split rtree page and update parent */return (rtr_page_split_and_insert(flags, cursor, offsets, heap, tuple, mtr));}if (!*heap) {*heap = mem_heap_create(1024);}n_uniq = dict_index_get_n_unique_in_tree(cursor->index);
func_start:ut_ad(tuple->m_heap != *heap);mem_heap_empty(*heap);*offsets = nullptr;ut_ad(mtr_memo_contains_flagged(mtr, dict_index_get_lock(cursor->index),MTR_MEMO_X_LOCK | MTR_MEMO_SX_LOCK) ||cursor->index->table->is_intrinsic());ut_ad(!dict_index_is_online_ddl(cursor->index) || (flags & BTR_CREATE_FLAG) ||cursor->index->is_clustered());ut_ad(rw_lock_own_flagged(dict_index_get_lock(cursor->index),RW_LOCK_FLAG_X | RW_LOCK_FLAG_SX) ||cursor->index->table->is_intrinsic());block = btr_cur_get_block(cursor);page = buf_block_get_frame(block);page_zip = buf_block_get_page_zip(block);ut_ad(mtr_is_block_fix(mtr, block, MTR_MEMO_PAGE_X_FIX, cursor->index->table));ut_ad(!page_is_empty(page));/* try to insert to the next page if possible before split */rec =btr_insert_into_right_sibling(flags, cursor, offsets, *heap, tuple, mtr);if (rec != nullptr) {return (rec);}page_no = block->page.id.page_no();/* 1. Decide the split record; split_rec == NULL means that thetuple to be inserted should be the first record on the upperhalf-page */insert_left = FALSE;if (n_iterations > 0) {direction = FSP_UP;hint_page_no = page_no + 1;split_rec = btr_page_get_split_rec(cursor, tuple);if (split_rec == nullptr) {insert_left =btr_page_tuple_smaller(cursor, tuple, offsets, n_uniq, heap);}} else if (btr_page_get_split_rec_to_right(cursor, &split_rec)) {direction = FSP_UP;hint_page_no = page_no + 1;} else if (btr_page_get_split_rec_to_left(cursor, &split_rec)) {direction = FSP_DOWN;hint_page_no = page_no - 1;ut_ad(split_rec);} else {direction = FSP_UP;hint_page_no = page_no + 1;/* If there is only one record in the index page, wecan't split the node in the middle by default. We needto determine whether the new record will be insertedto the left or right. */if (page_get_n_recs(page) > 1) {split_rec = page_get_middle_rec(page);} else if (btr_page_tuple_smaller(cursor, tuple, offsets, n_uniq, heap)) {split_rec = page_rec_get_next(page_get_infimum_rec(page));} else {split_rec = nullptr;}}/* 2. Allocate a new page to the index */new_block = btr_page_alloc(cursor->index, hint_page_no, direction,btr_page_get_level(page, mtr), mtr, mtr);/* New page could not be allocated */if (!new_block) {return nullptr;}new_page = buf_block_get_frame(new_block);new_page_zip = buf_block_get_page_zip(new_block);btr_page_create(new_block, new_page_zip, cursor->index,btr_page_get_level(page, mtr), mtr);/* 3. Calculate the first record on the upper half-page, and thefirst record (move_limit) on original page which ends up on theupper half */if (split_rec) {first_rec = move_limit = split_rec;*offsets =rec_get_offsets(split_rec, cursor->index, *offsets, n_uniq, heap);insert_left = cmp_dtuple_rec(tuple, split_rec, cursor->index, *offsets) < 0;if (!insert_left && new_page_zip && n_iterations > 0) {/* If a compressed page has already been split,avoid further splits by inserting the recordto an empty page. */split_rec = nullptr;goto insert_empty;}} else if (insert_left) {ut_a(n_iterations > 0);first_rec = page_rec_get_next(page_get_infimum_rec(page));move_limit = page_rec_get_next(btr_cur_get_rec(cursor));} else {insert_empty:ut_ad(!split_rec);ut_ad(!insert_left);buf =UT_NEW_ARRAY_NOKEY(byte, rec_get_converted_size(cursor->index, tuple));first_rec = rec_convert_dtuple_to_rec(buf, cursor->index, tuple);move_limit = page_rec_get_next(btr_cur_get_rec(cursor));}/* 4. Do first the modifications in the tree structure */btr_attach_half_pages(flags, cursor->index, block, first_rec, new_block,direction, mtr);/* If the split is made on the leaf level and the insert will fiton the appropriate half-page, we may release the tree x-latch.We can then move the records after releasing the tree latch,thus reducing the tree latch contention. */if (split_rec) {insert_will_fit =!new_page_zip &&btr_page_insert_fits(cursor, split_rec, offsets, tuple, heap);} else {if (!insert_left) {UT_DELETE_ARRAY(buf);buf = nullptr;}insert_will_fit =!new_page_zip &&btr_page_insert_fits(cursor, nullptr, offsets, tuple, heap);}if (!srv_read_only_mode && !cursor->index->table->is_intrinsic() &&insert_will_fit && page_is_leaf(page) &&!dict_index_is_online_ddl(cursor->index)) {mtr->memo_release(dict_index_get_lock(cursor->index),MTR_MEMO_X_LOCK | MTR_MEMO_SX_LOCK);/* NOTE: We cannot release root block latch here, because ithas segment header and already modified in most of cases.*/}/* 5. Move then the records to the new page */if (direction == FSP_DOWN) {/*       fputs("Split left\n", stderr); */if (false
#ifdef UNIV_ZIP_COPY|| page_zip
#endif /* UNIV_ZIP_COPY */|| !page_move_rec_list_start(new_block, block, move_limit,cursor->index, mtr)) {/* For some reason, compressing new_page failed,even though it should contain fewer records thanthe original page.  Copy the page byte for byteand then delete the records from both pagesas appropriate.  Deleting will always succeed. */ut_a(new_page_zip);page_zip_copy_recs(new_page_zip, new_page, page_zip, page, cursor->index,mtr);page_delete_rec_list_end(move_limit - page + new_page, new_block,cursor->index, ULINT_UNDEFINED, ULINT_UNDEFINED,mtr);/* Update the lock table and possible hash index. */if (!dict_table_is_locking_disabled(cursor->index->table)) {lock_move_rec_list_start(new_block, block, move_limit,new_page + PAGE_NEW_INFIMUM);}btr_search_move_or_delete_hash_entries(new_block, block, cursor->index);/* Delete the records from the source page. */page_delete_rec_list_start(move_limit, block, cursor->index, mtr);}left_block = new_block;right_block = block;if (!dict_table_is_locking_disabled(cursor->index->table)) {lock_update_split_left(right_block, left_block);}} else {/*     fputs("Split right\n", stderr); */if (false
#ifdef UNIV_ZIP_COPY|| page_zip
#endif /* UNIV_ZIP_COPY */|| !page_move_rec_list_end(new_block, block, move_limit, cursor->index,mtr)) {/* For some reason, compressing new_page failed,even though it should contain fewer records thanthe original page.  Copy the page byte for byteand then delete the records from both pagesas appropriate.  Deleting will always succeed. */ut_a(new_page_zip);page_zip_copy_recs(new_page_zip, new_page, page_zip, page, cursor->index,mtr);page_delete_rec_list_start(move_limit - page + new_page, new_block,cursor->index, mtr);/* Update the lock table and possible hash index. */if (!dict_table_is_locking_disabled(cursor->index->table)) {lock_move_rec_list_end(new_block, block, move_limit);}ut_ad(!dict_index_is_spatial(index));btr_search_move_or_delete_hash_entries(new_block, block, cursor->index);/* Delete the records from the source page. */page_delete_rec_list_end(move_limit, block, cursor->index,ULINT_UNDEFINED, ULINT_UNDEFINED, mtr);}left_block = block;right_block = new_block;if (!dict_table_is_locking_disabled(cursor->index->table)) {lock_update_split_right(right_block, left_block);}}#ifdef UNIV_ZIP_DEBUGif (page_zip) {ut_a(page_zip_validate(page_zip, page, cursor->index));ut_a(page_zip_validate(new_page_zip, new_page, cursor->index));}
#endif /* UNIV_ZIP_DEBUG *//* At this point, split_rec, move_limit and first_rec may pointto garbage on the old page. *//* 6. The split and the tree modification is now completed. Decide thepage where the tuple should be inserted */if (insert_left) {insert_block = left_block;} else {insert_block = right_block;}/* 7. Reposition the cursor for insert and try insertion */page_cursor = btr_cur_get_page_cur(cursor);page_cur_search(insert_block, cursor->index, tuple, page_cursor);rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index, offsets, heap,mtr);#ifdef UNIV_ZIP_DEBUG{page_t *insert_page = buf_block_get_frame(insert_block);page_zip_des_t *insert_page_zip = buf_block_get_page_zip(insert_block);ut_a(!insert_page_zip ||page_zip_validate(insert_page_zip, insert_page, cursor->index));}
#endif /* UNIV_ZIP_DEBUG */if (rec != nullptr) {goto func_exit;}/* 8. If insert did not fit, try page reorganization.For compressed pages, page_cur_tuple_insert() will haveattempted this already. */if (page_cur_get_page_zip(page_cursor) ||!btr_page_reorganize(page_cursor, cursor->index, mtr)) {goto insert_failed;}rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index, offsets, heap,mtr);if (rec == nullptr) {/* The insert did not fit on the page: loop back to thestart of the function for a new split */insert_failed:/* We play safe and reset the free bits for new_page */if (!cursor->index->is_clustered() &&!cursor->index->table->is_temporary()) {ibuf_reset_free_bits(new_block);ibuf_reset_free_bits(block);}n_iterations++;ut_ad(n_iterations < 2 || buf_block_get_page_zip(insert_block));ut_ad(!insert_will_fit);goto func_start;}func_exit:/* Insert fit on the page: update the free bits for theleft and right pages in the same mtr * /if (!cursor->index->is_clustered() && !cursor->index->table->is_temporary() &&page_is_leaf(page)) {ibuf_update_free_bits_for_two_pages_low(left_block, right_block, mtr);}MONITOR_INC(MONITOR_INDEX_SPLIT);ut_ad(page_validate(buf_block_get_frame(left_block), cursor->index));ut_ad(page_validate(buf_block_get_frame(right_block), cursor->index));ut_ad(!rec || rec_offs_validate(rec, cursor->index, * offsets));

基本上索引和数据在innodb中都在字典及页处理部分中,更多的细节可以查看相关的storage/include 以及相关的dict路径下的相关代码。换句话说,可以在include中的gis0tree.h 和gistree.ic中有对一些更细节的数据处理的函数,不过,在此引擎中,对树的描述相对分散一些,毕竟聚簇索引要保障在描述索引时还要描述数据,所以这点要看明白。
在MySql5.5以后,默认的数据库引擎是innodb而之间是MyISAM。而它的索引数据是分开来设计的,就比较好看清楚了。

五、总结

说实话,已经有多年不正经写Sql语句了,更多的则是关注于数据底层的细节,特别是针对近些年来的一些NOSQL型数据库,花费了不少的精力。但回过头来看,整个数据库解决的不外乎两个问题:一个是存储量大;另外一个是CRUD快。涉及到具体的实现,就需要考虑各种安全、并行。更要考虑事务和一致性,还要考虑对分布式的支持等等。数据库技术是一门相当复杂的技术,从上到下,从理论到实践,都在互相不断促进着。
索引只是其中的重要的一环,要想用好索引,知道索引底层是如何实现的,能更好的有针对性的解决在实际中遇到的索引问题。不同的数据库,可能实现的机制略有不同,但是原理基本都是类似的。好好学习,天天向上。

mysql源码分析——索引的数据结构相关推荐

  1. 转 MySQL源码分析

    看到一个不错的介绍,原址如下: http://software.intel.com/zh-cn/blogs/2010/08/20/mysql0/ MySQL源码分析(0):编译安装及调试 作者: Yu ...

  2. v64.06 鸿蒙内核源码分析(索引节点) | 谁是文件系统最重要的概念 | 百篇博客分析OpenHarmony源码

    子曰:"君子博学于文,约之以礼,亦可以弗畔矣夫!" <论语>:颜渊篇 百篇博客系列篇.本篇为: v64.xx 鸿蒙内核源码分析(索引节点篇) | 谁是文件系统最重要的概 ...

  3. MySQL 源码分析 binlog 编号上限

    MySQL 源码分析 binlog 编号上限 更新时间:2022-10-30 文章目录 MySQL 源码分析 binlog 编号上限 内容声明 问题描述 测试想法 问题测试 源码说明 MAX_LOG_ ...

  4. mysql源码分析——InnoDB引擎启动分析

    一.InnoDB启动 在MySql中,InnoDB的启动流程其实是很重要的.一些更细节的问题,就藏在了这其中.在前面分析过整个数据库启动的流程,本篇就具体分析一下InnoDB引擎启动所做的各种动作.在 ...

  5. MySQL 源码分析 v2.0

    第一节 mysql编译 (一).参考 https://blog.jcole.us/innodb/ https://www.cnblogs.com/zengkefu/p/5674503.html htt ...

  6. postgreSQL源码分析——索引的建立与使用——GIST索引(2)

    2021SC@SDUSC 本篇博客主要讲解GiST索引创建以及删除的相关函数 这里写目录标题 GIST创建 相关数据结构 GISTBuildState GISTInsertStack gistbuil ...

  7. Nginx源码分析:核心数据结构ngx_cycle_t与内存池概述

    nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> 核心数据结构与内存池概述 在Nginx中的核心数据结构就是ngx_cycle_t结构,在初始 ...

  8. mysql源码分析书籍_从源码分析 MySQL 死锁问题入门

    链接:https://juejin.im/post/5ce287326fb9a07ea8039d70 这篇文章主要讲的是如何通过调试 MySQL 源码,知道一条 SQL 真正会拿哪些锁,不再抓虾,瞎猜 ...

  9. postgreSQL源码分析——索引的建立与使用——Hash索引(2)

    2021SC@SDUSC 目录 Hash索引创建 hashbuild函数 _hash_init函数 Hash索引的插入 hashinsert函数 _hash_doinsert函数 总结 Hash索引创 ...

最新文章

  1. svn: Working copy locked
  2. 团队博客(第四周)-“名字好难想”
  3. AI式剥削:数据标注人员日薪低至51块钱
  4. 将矩阵转为一行_矩阵与矩阵乘积简介
  5. OS / 总线锁和缓存一致性
  6. SAP Spartacus Multi-Site Configuration
  7. [渝粤教育] 西南政法大学 法理学 参考 资料
  8. 软件测试常见笔试面试题(二)
  9. 基于python的毕业论文-基于python的飞机大战小游戏毕业论文设计和代码
  10. 状态机和UCOSII编程的比较
  11. Mysql之Specified key was too long; max key length is 767 bytes
  12. 什么是Lora Mesh网络
  13. 微软ipv6服务器,IPv6用户危险了!Win10出现严重安全漏洞
  14. 美团滑块(1-18,js逆向)
  15. 巫师3储物箱在哪_巫师3全宝藏宝箱地图分享 各种宝藏的具体位置
  16. c语言平时成绩占总分多少,平时成绩占多少啊 大学
  17. 地理空间数据格式——OGC-GML
  18. 掌握成为优秀财务的核心能力
  19. 原根的存在性 几道例题
  20. UVA 168 - Theseus and the Minotaur

热门文章

  1. 一文解决IDEA中文乱码问题
  2. 内网云盘如何内网穿透实现公网访问
  3. 珈创生物上市再次失败:先后折戟科创板、创业板,郑从义为董事长
  4. 1分钟搭建VPN服务器
  5. Vue开发登录组件(附下载)
  6. 微信公众号url认证(服务器认证)
  7. AIGC与AidLux互联应用—Aidlux端AIGC测评
  8. 排序问题排查Comparison method violates its general contract!
  9. 问题 A: 草地排水
  10. 吊打BERT、GPT、DALL·E,跨模态榜单新霸主诞生!