您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

MySQL源码:索引相关的数据结构(前篇)_MySQL

2025/6/26 3:51:43发布7次查看
本文将尝试介绍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`))
createtable`users`(
`id`int(11)notnull,
`nick`varchar(32)defaultnull,
`reg_date`datetimedefaultnull,
primarykey(`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}
(gdb)ps->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=0x7f651401fc11ind_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数组,存储
#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'}
(gdb)ps->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}, ...}
(gdb)p *s->table->key_info[1]->key_part[0]->field
$36={...table=0x7f6514023d30,
...field_name=0x7f651401fcf4nick,
...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 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 else1373 packet->append(string_with_len(key ));...1380 for (uint j=0 ; j 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 }
1351for(uinti=0;ikeys;i++,key_info++)
1352{1353key_part_info *key_part=key_info->key_part;
...1357if(i==primary_key&&!strcmp(key_info->name,primary_key_name))
1358{1359found_primary=1;
1364packet->append(string_with_len(primary key));
1365}1366elseif(key_info->flags&ha_nosame)
1367packet->append(string_with_len(unique key ));
...1372else1373packet->append(string_with_len(key ));
...1380for(uintj=0;jkey_parts;j++,key_part++)
1381{...1401}1402packet->append(')');
1403store_key_options(thd,packet,table,key_info);
1404if(key_info->parser)
1405{...1410}1411}
小结:
(1) 可以看到mysql如何遍历一个表的所有索引
key_info= table->key_info;for (uint i=0 ; i keys ; i++,key_info++){...}
key_info=table->key_info;
for(uinti=0;ikeys;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_parts ; j++,key_part++){...}
key_part_info *key_part=key_info->key_part;
for(uintj=0;jkey_parts;j++,key_part++)
{...}
(4) 查看完整的这个函数还可以看到mysql如何读取数据表的各个column
文章来自:orczhou
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product