思考mysql内核之初级系列5informationschema不是innodb数据字典.docx

上传人:b****6 文档编号:7762869 上传时间:2023-01-26 格式:DOCX 页数:11 大小:19.40KB
下载 相关 举报
思考mysql内核之初级系列5informationschema不是innodb数据字典.docx_第1页
第1页 / 共11页
思考mysql内核之初级系列5informationschema不是innodb数据字典.docx_第2页
第2页 / 共11页
思考mysql内核之初级系列5informationschema不是innodb数据字典.docx_第3页
第3页 / 共11页
思考mysql内核之初级系列5informationschema不是innodb数据字典.docx_第4页
第4页 / 共11页
思考mysql内核之初级系列5informationschema不是innodb数据字典.docx_第5页
第5页 / 共11页
点击查看更多>>
下载资源
资源描述

思考mysql内核之初级系列5informationschema不是innodb数据字典.docx

《思考mysql内核之初级系列5informationschema不是innodb数据字典.docx》由会员分享,可在线阅读,更多相关《思考mysql内核之初级系列5informationschema不是innodb数据字典.docx(11页珍藏版)》请在冰豆网上搜索。

思考mysql内核之初级系列5informationschema不是innodb数据字典.docx

思考mysql内核之初级系列5informationschema不是innodb数据字典

思考mysql内核之初级系列5---information_schema不是innodb数据字典

上次谈到了innodb缓冲区里面有些页被使用了,这些中有些被数据字典用了。

那么什么是数据字典呢?

bingxi和alex继续思考。

1)information_schema不是innodb数据字典

bingxi:

“alex,我觉得information_schema这个里面存储的不是数据字典,为了准确起见,换个说法,information_schema不是innodb数据字典。

alex:

“是的,innodb一直有数据字典的概念,而information_schema是在mysql5之后才出现的。

因此,information_schema不是innodb数据字典。

bingxi:

“alex,这样说有点牵强。

我们首先举个例子吧。

在手册里面,有这么一段话:

23.4.TheINFORMATION_SCHEMASTATISTICSTable

TheSTATISTICStableprovidesinformationabouttableindexes.

这段话表达的意思是:

information_schema.statistics存储的是表索引信息。

我们在test数据库下面建立一个表t1,并且在c1上有一个索引,语句如下:

createtabletest.t1

idint,

namevarchar(20),

keyit1id(id)

)engine=innodb;

接着我们查询statistics表中t1的索引信息:

mysql>select*frominformation_schema.statisticswheretable_name='t1'\G;

***************************1.row***************************

TABLE_CATALOG:

NULL

TABLE_SCHEMA:

test

TABLE_NAME:

t1

NON_UNIQUE:

1

INDEX_SCHEMA:

test

INDEX_NAME:

it1id

SEQ_IN_INDEX:

1

COLUMN_NAME:

id

COLLATION:

A

CARDINALITY:

0

SUB_PART:

NULL

PACKED:

NULL

NULLABLE:

YES

INDEX_TYPE:

BTREE

COMMENT:

1rowinset(0.02sec)

ERROR:

Noqueryspecified

从中我们可以查到索引的信息,t1表真正只有一个索引么?

呵呵,这里先卖个关子,在讲innodb数据字典的时候再说这个。

现在我们聚焦在it1c1索引上,这些信息确实可以看到一些索引的信息,但是这个不是数据字典表,而仅仅只能供用户从外部查看使用,不能供mysql内核使用。

比如,该索引在数据文件里面存储在什么地方?

不知道根页信息,就没法去使用索引。

我们再看看真正的innodb数据字典中包含的内容。

(见文件D:

\mysql-5.1.7-beta\storage\innobase\include\dict0mem.h)

/*Datastructureforanindex*/

structdict_index_struct{

……

dict_table_t*table;//指向所属的table字典

ulintspace;//索引所在的space

……

dict_tree_t*tree;//索引数结构

……

};

/*Datastructureforanindextree*/

structdict_tree_struct{

……

ulintspace;//索引所在的space

ulintpage;//索引的根结点页号

……

};

通过space,page我们就可以实实在在地在访问该索引。

alex:

“顶你,是这样的。

通过showcreate我们还可以看出这些表是临时表。

mysql>showcreatetableinformation_schema.tables\G;

***************************1.row***************************

Table:

TABLES

CreateTable:

CREATETEMPORARYTABLE`TABLES`(

`TABLE_CATALOG`varchar(512)defaultNULL,

……

)ENGINE=MEMORYDEFAULTCHARSET=utf8

1rowinset(0.00sec)

ERROR:

Noqueryspecified

bingxi:

“是的”

2)information_schema内容分析

alex:

“bingxi,尽管information_schema不是innodb的数据字典,我们还是来摸索下information_schema对应的代码吧。

主要的代码目录如下:

D:

\mysql-5.1.7-beta\sql\sql_show.h

D:

\mysql-5.1.7-beta\sql\sql_show.cpp

bingxi:

“alex,从文件名我们可以看到show,是不是showstatus,showvariables,showprocesslist等也是在这个文件里面执行。

alex:

“是的,没错。

我们开始吧,先从两个数据结构开始。

先看schema_tables数组。

ST_SCHEMA_TABLEschema_tables[]=

{

{"CHARACTER_SETS",charsets_fields_info,create_schema_table,

fill_schema_charsets,make_character_sets_old_format,0,-1,-1,0},

……

{"STATUS",variables_fields_info,create_schema_table,fill_status,

make_old_format,0,-1,-1,1},

{"TABLES",tables_fields_info,create_schema_table,

get_all_tables,make_old_format,get_schema_tables_record,1,2,0},

{"TABLE_CONSTRAINTS",table_constraints_fields_info,create_schema_table,

get_all_tables,0,get_schema_constraints_record,3,4,0},

……

};

数组有26个成员,而information_schema的5.1.7版本中只有22个表。

这是可以理解的,比如该数组里面有status、variable,而这个在information_schema下是没有。

我们通过showstatus,showvariables来执行。

我们接着说这个数组的成员,每个成员是一个数组结构的取值,见下面的定义:

typedefstructst_schema_table

{

constchar*table_name;

ST_FIELD_INFO*fields_info;

TABLE*(*create_table)(THD*thd,structst_table_list*table_list);

int(*fill_table)(THD*thd,structst_table_list*tables,COND*cond);

int(*old_format)(THD*thd,structst_schema_table*schema_table);

int(*process_table)(THD*thd,structst_table_list*tables,

TABLE*table,boolres,constchar*base_name,

constchar*file_name);

intidx_field1,idx_field2;

boolhidden;

}ST_SCHEMA_TABLE;

我们以tables这样表为例

{"TABLES",tables_fields_info,create_schema_table,

get_all_tables,make_old_format,get_schema_tables_record,1,2,0},

tables_fields_info表示的就是。

ST_FIELD_INFOtables_fields_info[]=

{

{"TABLE_CATALOG",FN_REFLEN,MYSQL_TYPE_STRING,0,1,0},

{"TABLE_SCHEMA",NAME_LEN,MYSQL_TYPE_STRING,0,0,0},

{"TABLE_NAME",NAME_LEN,MYSQL_TYPE_STRING,0,0,"Name"},

{"TABLE_TYPE",NAME_LEN,MYSQL_TYPE_STRING,0,0,0},

{"ENGINE",NAME_LEN,MYSQL_TYPE_STRING,0,1,"Engine"},

{"VERSION",21,MYSQL_TYPE_LONG,0,1,"Version"},

{"ROW_FORMAT",10,MYSQL_TYPE_STRING,0,1,"Row_format"},

{"TABLE_ROWS",21,MYSQL_TYPE_LONG,0,1,"Rows"},

{"AVG_ROW_LENGTH",21,MYSQL_TYPE_LONG,0,1,"Avg_row_length"},

{"DATA_LENGTH",21,MYSQL_TYPE_LONG,0,1,"Data_length"},

{"MAX_DATA_LENGTH",21,MYSQL_TYPE_LONG,0,1,"Max_data_length"},

{"INDEX_LENGTH",21,MYSQL_TYPE_LONG,0,1,"Index_length"},

{"DATA_FREE",21,MYSQL_TYPE_LONG,0,1,"Data_free"},

{"AUTO_INCREMENT",21,MYSQL_TYPE_LONG,0,1,"Auto_increment"},

{"CREATE_TIME",0,MYSQL_TYPE_TIMESTAMP,0,1,"Create_time"},

{"UPDATE_TIME",0,MYSQL_TYPE_TIMESTAMP,0,1,"Update_time"},

{"CHECK_TIME",0,MYSQL_TYPE_TIMESTAMP,0,1,"Check_time"},

{"TABLE_COLLATION",64,MYSQL_TYPE_STRING,0,1,"Collation"},

{"CHECKSUM",21,MYSQL_TYPE_LONG,0,1,"Checksum"},

{"CREATE_OPTIONS",255,MYSQL_TYPE_STRING,0,1,"Create_options"},

{"TABLE_COMMENT",80,MYSQL_TYPE_STRING,0,0,"Comment"},

{0,0,MYSQL_TYPE_STRING,0,0,0}

};

这个表示的就是tables表的字段,不考虑这行’{0,0,MYSQL_TYPE_STRING,0,0,0}’,对比下desctables;两边是一样的。

Bingxi:

“我顶你,我们通过一个例子来看吧,以showstatus为例。

{"STATUS",variables_fields_info,create_schema_table,fill_status,

make_old_format,0,-1,-1,1},

//根据对比,我们可以知道:

//create_schema_table的功能是:

TABLE*(*create_table)

//fill_status的功能是:

int(*fill_table)

//make_old_format的功能是:

int(*old_format),这个可以暂时不调试

首先我们查看函数mysql_schema_table,在其中调用了函数create_schema_table。

intmysql_schema_table(THD*thd,LEX*lex,TABLE_LIST*table_list)

{

……

//table_list->schema_table对应的结构就是st_schema_table

//对应的值为:

{"STATUS",variables_fields_info,create_schema_table,fill_status,

//make_old_format,0,-1,-1,1},

//因此这里的create_table等于访问create_schema_table

if(!

(table=table_list->schema_table->create_table(thd,table_list)))

{

DBUG_RETURN

(1);

}

……

}

create_schema_table函数作用是什么呢?

从名字我们可以看出,就是创建表,创建status的临时表。

表的字段有两个:

Variable_name、Value。

见下面的代码。

TABLE*create_schema_table(THD*thd,TABLE_LIST*table_list)

{

……

Listfield_list;

ST_SCHEMA_TABLE*schema_table=table_list->schema_table;

ST_FIELD_INFO*fields_info=schema_table->fields_info;

……

//fields_info就是schema_table->fields_info,里面记录了查询字段

//第一个fields_info->field_name的值是'Variable_name'

//根据这个值创建了一个item实例,然后丢到field_list这个list里面

//第二个fields_info->field_name的值是'Value'

//同样根据这个值,再创一个item,同样丢到field_list这个list里面

//这样field_list就描述了临时表的列信息

for(;fields_info->field_name;fields_info++)

{

……

//屏蔽调ields_info->field_type的差异性

item->max_length=fields_info->field_length*cs->mbmaxlen;

item->set_name(fields_info->field_name,

strlen(fields_info->field_name),cs);

……

field_list.push_back(item);

item->maybe_null=fields_info->maybe_null;

field_count++;

}

TMP_TABLE_PARAM*tmp_table_param=

(TMP_TABLE_PARAM*)(thd->calloc(sizeof(TMP_TABLE_PARAM)));

tmp_table_param->init();

tmp_table_param->table_charset=cs;

tmp_table_param->field_count=field_count;

tmp_table_param->schema_table=1;

SELECT_LEX*select_lex=thd->lex->current_select;

//调用函数create_tmp_table

//可以看到参数中有field_list,也就是字段列表有了

//table_list->alias的值是STATUS

//于是就是创建了临时表

if(!

(table=create_tmp_table(thd,tmp_table_param,

field_list,(ORDER*)0,0,0,

(select_lex->options|thd->options|

TMP_TABLE_ALL_COLUMNS),

HA_POS_ERROR,table_list->alias)))

……

}

创建了临时表,但是光有临时表是不够的,因此在查询执行时,需要将值进行填充

void

JOIN:

:

exec()

{

……

if((curr_join->select_lex->options&OPTION_SCHEMA_TABLE)&&

get_schema_tables_result(curr_join))

{

DBUG_VOID_RETURN;

}

……

get_schema_tables_result函数就是调用fill_status的地方,见函数。

boolget_schema_tables_result(JOIN*join)

{

……

for(JOIN_TAB*tab=join->join_tab;tab

{

……

//table_list->schema_table对应的结构就是st_schema_table

//对应的值为:

{"STATUS",variables_fields_info,create_schema_table,fill_status,

//make_old_format,0,-1,-1,1},

//因此这里的fill_table等于访问fill_status

if(table_list->schema_table->fill_table(thd,table_list,

tab->select_cond))

result=1;

table_list->is_schema_table_processed=TRUE;

……

}

……

}

于是执行fill_status进行填充数据的操作。

intfill_status(THD*thd,TABLE_LIST*tables,COND*cond)

{

DBUG_ENTER("fill_status");

LEX*lex=thd->lex;

constchar*wild=lex->wild?

lex->wild->ptr():

NullS;

intres=0;

STATUS_VARtmp;

pthread_mutex_lock(&LOCK_status);

//如果是showglobal,则需要执行calc_sum_of_all_status进行累加。

if(lex->option_type==OPT_GLOBAL)

calc_sum_of_all_status(&tmp);

//进行数据插入操作

res=show_status_array(thd,wild,

(SHOW_VAR*)all_status_vars.buffer,

OPT_GLOBAL,

(lex->option_type==OPT_GLOBAL?

&tmp:

&thd->status_var),"",tables->table);

pthread_mutex_unlock(&LOCK_status);

DBUG_RETURN(res);

}

为了了解得更清楚,我们再看下show_status_array函数。

staticboolshow_status_array(THD*thd,constchar*wild,

SHOW_VAR*variables,

enumenum_var_typevalue_type,

structsystem_status_var*status_var,

constchar*prefix,TABLE*table)

{

//传递过来的variables是全局变量:

(SHOW_VAR*)all_status_vars.buffer

//因此对于变量执行循环操作

for(;variables->name;variables++)

{

……

restore_record(table,s->default_values);

table->field[0]->store(name_buffer,strlen(name_buffer),

system_charset_info);

table->field[1]->store(pos,(uint32)(end-pos),system_charset_info);

//将记录插入表

if(schema_table_store_record(thd,table))

DBUG_RETURN(TRUE);

……

}

……

}

执行到这里,status表里面已经有了所有的数据。

然后继续执行,显示出来就行了。

Alex:

“我明白了。

其它的也是类似的,差异性也是有的,比如tables需要进行数据文件夹的扫描,呵呵。

Bingxi:

“是的,都差不多的。

Alex:

“我的建议是,将该cpp文件里面的函数都设置断点,然后每个语句执行一下。

比如select*frominformation_schema.tables\G,用这样的方法把该模式下的22个表测试一边,并测试下show语句,showprocesslist,showvariable,showceatetable

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 小学教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1