思考mysql内核之初级系列5informationschema不是innodb数据字典Word格式文档下载.docx
《思考mysql内核之初级系列5informationschema不是innodb数据字典Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《思考mysql内核之初级系列5informationschema不是innodb数据字典Word格式文档下载.docx(11页珍藏版)》请在冰豆网上搜索。
t1
NON_UNIQUE:
1
INDEX_SCHEMA:
INDEX_NAME:
it1id
SEQ_IN_INDEX:
COLUMN_NAME:
id
COLLATION:
A
CARDINALITY:
0
SUB_PART:
PACKED:
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{
ulintpage;
//索引的根结点页号
通过space,page我们就可以实实在在地在访问该索引。
“顶你,是这样的。
通过showcreate我们还可以看出这些表是临时表。
showcreatetableinformation_schema.tables\G;
Table:
TABLES
CreateTable:
CREATETEMPORARYTABLE`TABLES`(
`TABLE_CATALOG`varchar(512)defaultNULL,
……
)ENGINE=MEMORYDEFAULTCHARSET=utf8
1rowinset(0.00sec)
“是的”
2)information_schema内容分析
“bingxi,尽管information_schema不是innodb的数据字典,我们还是来摸索下information_schema对应的代码吧。
主要的代码目录如下:
D:
\mysql-5.1.7-beta\sql\sql_show.h
\mysql-5.1.7-beta\sql\sql_show.cpp
“alex,从文件名我们可以看到show,是不是showstatus,showvariables,showprocesslist等也是在这个文件里面执行。
“是的,没错。
我们开始吧,先从两个数据结构开始。
先看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_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"
Rows"
AVG_ROW_LENGTH"
Avg_row_length"
DATA_LENGTH"
Data_length"
MAX_DATA_LENGTH"
Max_data_length"
INDEX_LENGTH"
Index_length"
DATA_FREE"
Data_free"
AUTO_INCREMENT"
Auto_increment"
CREATE_TIME"
0,MYSQL_TYPE_TIMESTAMP,0,1,"
Create_time"
UPDATE_TIME"
Update_time"
CHECK_TIME"
Check_time"
TABLE_COLLATION"
64,MYSQL_TYPE_STRING,0,1,"
Collation"
CHECKSUM"
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为例。
//根据对比,我们可以知道:
//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
//对应的值为:
{"
//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<
Item>
field_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->
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;
set_name(fields_info->
field_name,
strlen(fields_info->
field_name),cs);
field_list.push_back(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();
table_charset=cs;
field_count=field_count;
schema_table=1;
SELECT_LEX*select_lex=thd->
lex->
current_select;
//调用函数create_tmp_table
//可以看到参数中有field_list,也就是字段列表有了
//table_list->
alias的值是STATUS
//于是就是创建了临时表
(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<
tmp_join_tab;
tab++)
{
//因此这里的fill_table等于访问fill_status
if(table_list->
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(&
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
//因此对于变量执行循环操作
variables->
name;
variables++)
restore_record(table,s->
default_values);
table->
field[0]->
store(name_buffer,strlen(name_buffer),
system_charset_info);
field[1]->
store(pos,(uint32)(end-pos),system_charset_info);
//将记录插入表
if(schema_table_store_record(thd,table))
DBUG_RETURN(TRUE);
执行到这里,status表里面已经有了所有的数据。
然后继续执行,显示出来就行了。
Alex:
“我明白了。
其它的也是类似的,差异性也是有的,比如tables需要进行数据文件夹的扫描,呵呵。
“是的,都差不多的。
“我的建议是,将该cpp文件里面的函数都设置断点,然后每个语句执行一下。
比如select*frominformation_schema.tables\G,用这样的方法把该模式下的22个表测试一边,并测试下show语句,showprocesslist,showvariable,showceatetable