http://www.orczhou.com/index.php/2012/11/mysql-source-code-data-structure-about-index/

本文将尝试介绍MySQL索引存储相关的数据结构。程序=数据结构+算法,了解数据结构,然后就可以进一步了解MySQL源码中如何使用索引,如何选择自己的执行计划。

1. MySQL如何描述某个数据表的索引

MySQL使用TABLE对象来描述一个数据表,那么数据表的索引是如何描述,索引的统计信息又是如何存储的呢? 例如我们有如下数据表:

CREATE TABLE `users` ( `id` int(11) NOT NULL, `nick` varchar(32) DEFAULT NULL, `reg_date` datetime DEFAULT NULL, PRIMARY KEY (`id`), KEY `IND_NICK` (`nick`), KEY `IND_REGDATE` (`reg_date`) )

该表有索引,PRIMARY KEY、IND_NICK、IND_REGDATE,我们来看看MySQL内部是如何存储这三个索引,以及如何使用这些索引的统计信息的。下图,描述了存储一个数据表索引的主要结构:

  • MySQL使用TABLE对象描述一个数据表,他的成员key_info(类型为KEY)描述这个表的全部索引
  • key_info是一个数组,每一个元素是一个KEY(vim -t KEY查看)对象,代表了一个索引,顺序的,整个数组代表了这个表的全部索引
  • key_info(KEY对象)的成员key_part,是指向KEY_PART_INFO数组的指针,该数组描述了某个索引所有的索引列信息,数组的每个元素代表了一个索引列
  • 最后,key_part的成员field指向该索引列对应的数据表字段

2. GDB打印观察索引信息

2.1 打印索引基本信息

某个索引(例如IND_NICK)的基本信息是存储在KEY结构(table->key_info数组)中,这里,我们来打印索引IND_NICK的基本信息来观察KEY结构:

(gdb) p s->table->key_info[1] $26 = { key_length = 67, flags = 104, key_parts = 1, extra_length = 3, usable_key_parts = 1, block_size = 1024, algorithm = HA_KEY_ALG_UNDEF, { parser = 0x0, parser_name = 0x0 }, key_part = 0x7f6514020860, name = 0x7f651401fc11 "IND_NICK", rec_per_key = 0x7f651401fa68, handler = { bdb_return_if_eq = 0 }, table = 0x7f6514023d30 }

key_length = 67: 表示这个索引入口长为67(不包括rowid),32*2 + 1(NULL) + VARCHAR变成信息

flags = 104 这是一个索引信息的标志位,存储了这个索引的一些重要属性,例如是不是唯一索引,索引中有没有变长字段,是不是一个全文索引等,104表示为二进制,即是1101000,也等于8+32+64,也就是HA_VAR_LENGTH_KEY|HA_BINARY_PACK_KEY|HA_NULL_PART_KEY

更多flags类型:

#define HA_NOSAME 1 /* Set if not dupplicated records */ #define HA_PACK_KEY 2 /* Pack string key to previous key */ #define HA_SPACE_PACK_USED 4 /* Test for if SPACE_PACK used */ #define HA_VAR_LENGTH_KEY 8 #define HA_AUTO_KEY 16 #define HA_BINARY_PACK_KEY 32 /* Packing of all keys to prev key */ #define HA_NULL_PART_KEY 64 #define HA_FULLTEXT 128 /* For full-text search */ #define HA_UNIQUE_CHECK 256 /* Check the key for uniqueness */ #define HA_SPATIAL 1024 /* For spatial search */ #define HA_NULL_ARE_EQUAL 2048 /* NULL in key are cmp as equal */ #define HA_GENERATED_KEY 8192 /* Automaticly generated key */

key_part = 0x7f6514020860 这个指针指向一个KEY_PART_INFO数组,存储了索引各个列的信息。

2.2 打印索引某一列的基本信息

(gdb) p s->table->key_info[1]->key_part[0] $29 = { field = 0x7f6514020588, offset = 5, null_offset = 0, length = 64, store_length = 67, key_type = 32768, fieldnr = 2, key_part_flag = 24, type = 15 '\017', null_bit = 1 '\001' }

field = 0x7f6514020588 指向这个索引列使用数据表的那一列

offset = 5 改索引列从索引串的第一个偏移开始

null_offset = 0 null信息存储偏移

length = 64, 索引串长度

store_length = 67, 整个索引入口长度

...

2.3 打印索引某列详情

(gdb) p *s->table->key_info[1]->key_part[0]->field $36 = { ... table = 0x7f6514023d30, ... field_name = 0x7f651401fcf4 "nick", ... key_start = { map = 2 }, part_of_key = { map = 2 }, part_of_key_not_clustered = { map = 2 }, part_of_sortkey = { map = 2 }, ... }

table = 0x7f6514023d30 指向该列所在的数据表

field_name = 0x7f651401fcf4 "nick" 列名

key_start = 2 包含这个字段且为索引第一个字段的索引编号,2的二进制是10,也就是第二索引以该字段为起始

3. MySQL源码中如何使用索引信息

下面摘抄函数store_create_info(显示SHOW CREATE TABLE命令)显示索引信息部分的代码如下:

1351 for (uint i=0 ; i < share->keys ; i++,key_info++) 1352 { 1353 KEY_PART_INFO *key_part= key_info->key_part; ... 1357 if (i == primary_key && !strcmp(key_info->name, primary_key_name)) 1358 { 1359 found_primary=1; 1364 packet->append(STRING_WITH_LEN("PRIMARY KEY")); 1365 } 1366 else if (key_info->flags & HA_NOSAME) 1367 packet->append(STRING_WITH_LEN("UNIQUE KEY ")); ... 1372 else 1373 packet->append(STRING_WITH_LEN("KEY ")); ... 1380 for (uint j=0 ; j < key_info->key_parts ; j++,key_part++) 1381 { ... 1401 } 1402 packet->append(')'); 1403 store_key_options(thd, packet, table, key_info); 1404 if (key_info->parser) 1405 { ... 1410 } 1411 }

小结:

(1) 可以看到MySQL如何遍历一个表的所有索引

key_info= table->key_info; for (uint i=0 ; i < share->keys ; i++,key_info++) { ... }

(2) 可以看到MySQL如何根据key_info->flags字段如何区分唯一索引,全文索引等

(3) 可以看到MySQL如何遍历一个索引的所有字段:

KEY_PART_INFO *key_part= key_info->key_part; for (uint j=0 ; j < key_info->key_parts ; j++,key_part++) { ... }

(4) 查看完整的这个函数还可以看到MySQL如何读取数据表的各个column

MySQL源码:索引相关的数据结构的更多相关文章

  1. MySQL源码 数据结构array

    MySQL源码中自己定义了许多数据结构,放在mysys的目录下,源码中通常都使用这些数据结构来组织存放数据,也更容易实现跨平台.   下面先来看下MySQL定义的动态数组: [源代码include/a ...

  2. MySQL源码 数据结构hash

    MySQL源码自定义了hash表,因为hash表具有O(1)的查询效率,所以,源码中大量使用了hash结构.下面就来看下hash表的定义: [源代码文件include/hash.h mysys/has ...

  3. MySQL源码分析以及目录结构 2

    原文地址:MySQL源码分析以及目录结构作者:jacky民工 主要模块及数据流经过多年的发展,mysql的主要模块已经稳定,基本不会有大的修改.本文将对MySQL的整体架构及重要目录进行讲述. 源码结 ...

  4. MySQL源码分析以及目录结构

    原文地址:MySQL源码分析以及目录结构作者:jacky民工 主要模块及数据流经过多年的发展,mysql的主要模块已经稳定,基本不会有大的修改.本文将对MySQL的整体架构及重要目录进行讲述. 源码结 ...

  5. mysql源码编译安装

    首先去官网http://dev.mysql.com/downloads/mysql/ 下载mysql源码.我下的是5.7.10 源码选择的是 Generic Linux (Architecture I ...

  6. 深入MySQL源码 学习方法 何登成专家

    MYSQL 技术圈 有哪些做得好,又注重分享的公司: Oracle MySQL, MariaDB, Percona,Google, FB, Twitter, Taobao, NetEase… 有哪些值 ...

  7. Mysql 源码编译教程贴

    题外话:这是一篇教程贴,不仅学的是mysql的编译,还是一些编译的知识.我也是一个菜鸟,写一些感悟和心得,有什么问题可以批评指正,谢谢! 如果只是为了安装请移到我的另一篇安装贴: Mysql安装贴 环 ...

  8. Linux(CentOS或RadHat)下MySQL源码安装

    安装环境: CentOS6.3 64位 软件: Mysql-5.6 所需包: gcc/g++ :MySQL 5.6开始,需要使用g++进行编译.cmake  :MySQL 5.5开始,使用cmake进 ...

  9. maridb\mysql 源码安装,以10.1.26版本为例

    mysql 源码安装(mariadb 10.1.26) 1.环境部署 1 安装cmake 源码安装三部曲或者yum install cmake2安装依赖包yum install -y ncurses- ...

随机推荐

  1. C语言中.h和.c文件解析(很精彩)

    C语言中.h和.c文件解析(很精彩)   简单的说其实要理解C文件与头文件(即.h)有什么不同之处,首先需要弄明白编译器的工作过程,一般说来编译器会做以下几个过程: 1.预处理阶段 2.词法与语法分析 ...

  2. nutch 索引

    nutch开发环境搭建     nutch-1.3导入eclipse     nutch-1.7导入eclipse nutch部署     nutch-1.3linux下部署     nutch-1. ...

  3. BZOJ 1639: [Usaco2007 Mar]Monthly Expense 月度开支

    Description Farmer John是一个令人惊讶的会计学天才,他已经明白了他可能会花光他的钱,这些钱本来是要维持农场每个月的正常运转的.他已经计算了他以后N(1<=N<=100 ...

  4. 将excel数据导入内表的函数

    call function 'TEXT_CONVERT_XLS_TO_SAP'    exporting      i_tab_raw_data       = lt_raw "开始行    ...

  5. 【技术帖】解决 Hudson jenkins 连接等待中 - Waiting for next av

    今天构建项目发现如下问题: jenkins 连接等待中 - Waiting for next available executor 左下角那块一直不运行构建,一直在连接等待. 于是,进入一级页面, 右 ...

  6. hdu 4433

    一道dp题,虽然知道是dp,但是不会做: 学习了ACM_cxlove大神的代码,终于明白了: 搬运工: dp[i][j][k]表示 前i个已经完全匹配,而这时候,第i+1个已经加了j位,第i+2位已经 ...

  7. Linux下fork()、vfork()、clone()和exec()的区别

    转自Linux下fork().vfork().clone()和exec()的区别 前三个和最后一个是两个类型.前三个主要是Linux用来创建新的进程(线程)而设计的,exec()系列函数则是用来用指定 ...

  8. Spring In Action 第4版笔记-第一章-001架构

    1.Spring’s fundamental mission: Spring simplifies Java development. 2.To back up its attack on Java ...

  9. CKFinder 2.4 ASP.NET 破解

    网上的破解教程对于2.4版本来说已经过时了. 以下是CKFinder 2.4 ASP.NET的亲测可用破解方法,经测试,只需修改两处代码. 打开ckfinder.js, 步骤1. 搜索替换如下代码: ...

  10. Wide character in print at a2.pl line 返回json 需要encode_utf8

    centos6.5:/root/test#cat a2.pl use Net::SMTP; use LWP::UserAgent; use HTTP::Cookies; use HTTP::Heade ...