思考mysql内核之初级系列5informationschema不是innodb数据字典.docx
- 文档编号:7762869
- 上传时间:2023-01-26
- 格式:DOCX
- 页数:11
- 大小:19.40KB
思考mysql内核之初级系列5informationschema不是innodb数据字典.docx
《思考mysql内核之初级系列5informationschema不是innodb数据字典.docx》由会员分享,可在线阅读,更多相关《思考mysql内核之初级系列5informationschema不是innodb数据字典.docx(11页珍藏版)》请在冰豆网上搜索。
思考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)
{
……
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
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 思考 mysql 内核 初级 系列 informationschema 不是 innodb 数据 字典