case描述:

  innodb中,父表和子表通过foreign constraint进行关联, 因为在更新数据时需要check 外键constraint,如果父表被大量的子表reference,
那么在open的时候,需要open所有的child table和所有的foreign constraint,导致时间过长,产生long semaphore wait 。

分析过程:

  case 用例:

CREATE TABLE `t1` (
`f1` int() NOT NULL,
PRIMARY KEY (`f1`)
) ENGINE=InnoDB CREATE TABLE `fk_1` (
`f1` int() NOT NULL,
PRIMARY KEY (`f1`),
CONSTRAINT `pc1` FOREIGN KEY (`f1`) REFERENCES `t1` (`f1`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB
...... 这里建了fk_[-]张表。

1. 背景:innodb数据字典

  innodb使用系统表空间保存表相关的数据字典,系统的数据字典包括:

  • SYS_TABLES
  • SYS_INDEXES
  • SYS_COLUMNS
  • SYS_FIELDS
  • SYS_FOREIGN
  • SYS_FOREIGN_COLS
  • SYS_STATS

  在load某个表的时候,分别从这些表中把表相关的index,column, index_field, foreign, foreign_col数据保存到dictionary cache中。
对应的内存对象分别是:dict_col_struct,dict_field_struct,dict_index_struct,dict_table_struct,dict_foreign_struct。
这些对象全局唯一,在dictionary cache只保留一份,并使用dict_sys->mutex进行同步保护,所有open的handler引用到这些对象上。

注意:系统的数据字典同样是innodb的聚簇索引表,并受redo保护。

  

2. open过程

入口函数ha_innobase::open()
dict_load_table:

1. 通过sys_tables系统表,load table相关的定义
2. 通过sys_indexes系统表,根据table_id load 所有相关index
3. 通过sys_columns系统表,根据table_id load 所有的columns
4. 通过sys_fields系统表,根据index_id load 所有index的field
5. 通过sys_foreign系统表,load所有关联的表和foreign key

在load这些定义的时候,过程都是:
  1. 通过某个字段,查找系统字典表
  2. 根据查询的记录建立内存对象,并加入到全局cache中

但在load foreign的时候,会有一些不同,因为foreign key于两张表相关联。下面详细介绍下load foreign的过程。

3. load foreign的详细过程

  如下图所示foreign的关联关系:

  

load的步骤:

3.1: 根据表名t1 查找sys_foreign. 而sys_foreign表上一共有三个索引:     

    index_1(id): cluster_index
    index_2(for_name): secondary_index
    index_3(ref_name): secondary_index

所以,根据for_name='t1', ref_name='t1'检索出来所有相关的foreign_id.

3.2: 根据3.1检索出来的foreign_id, load foreign对象,并打开相关fk_[1-10000]表。

3.3: 加入cache

  因为没有专门的cache,foreign分别加入到for_name->foreign_list, ref_name->refence_list
问题的关键:因为foreign是全局唯一的,但foreign又与两个表关联,所以,有可能在open 其它表的时候
已经打开过,所以,create foreign对象后,需要判断以下四个list,是否已经存在,如果存在就直接使用。

dict_foreign_find:分别查询这四个list,如果已经存在,则free新建的foreign对象,引用已经存在的。
    for_name->foreign_list
    for_name->refence_list
    ref_name->foreign_list
    ref_name->refence_list

如果不存在,把新建的foreign加入到for_name->foreign_list,ref_name->refence_list链表中。

4. 问题的原因:

  因为第一次load,所以find都没有找到,但这四个都是list,随着open的越来越多,检索的代价越来越大。
而整个过程中,都一直持有trx_sys->mutex,最终导致了long semaphore wait。

5. 问题改进方法:

  

  在MySQL 5.5.39版本中,进行了修复,修复的方法就是,除了foreign_list,referenced_list。
另外又增加了两个red_black tree,如下源码所示:

struct dict_table_struct{
table_id_t id;   /*!< id of the table */
mem_heap_t* heap; /*!< memory heap */
char* name;     /*!< table name */
UT_LIST_BASE_NODE_T(dict_foreign_t)
foreign_list;          /*!< list of foreign key constraints in the table; these refer to columns in other tables */
UT_LIST_BASE_NODE_T(dict_foreign_t)
referenced_list;/*!< list of foreign key constraints which refer to this table */
ib_rbt_t* foreign_rbt; /*!< a rb-tree of all foreign keys listed in foreign_list, sorted by foreign->id */
ib_rbt_t* referenced_rbt; /*!< a rb-tree of all foreign keys listed in referenced_list, sorted by foreign->id */

在初始化list的时候,初始化一份red_black tree. 在dict_foreign_find的过程中,直接查找rbt,这样查询的代价大大降低。

Innodb parent table open时导致crash的更多相关文章

  1. IE6 IE7: div中table宽度100%导致的宽度问题

    问题现象:定义了DOCTYPE的页面 当表格的内容比div的高度还要高时,div会出现滚动条,同时在IE6和IE7下会出现问题: IE6:此时table的100%宽度还是没有滚动条那是的宽度,出现滚动 ...

  2. MySQL 5.6 解决InnoDB: Error: Table "mysql"."innodb_table_stats" not found.问题

    在安装MySQL 5.6.30时,安装完成后,后台日志报如下警告信息:2016-05-27 12:25:27 7fabf86f7700 InnoDB: Error: Table "mysql ...

  3. 还原堆栈信息,分析地形系统使用ASTC格式的纹理导致Crash的问题

    0x00 前言 在这篇文章中,我们选择了过去一周Unity官方社区交流群中比较有代表性的几个问题,总结在这里和大家进行分享.主要涵盖了IL2CPP.Scripting.Virtual Reality. ...

  4. 【MySQL】5.6.x InnoDB Error Table mysql.innodb_table_stats not found

    [问题描述]: 检查error log的时候发现大量warnings: [Warning] InnoDB Error Table mysql.innodb_index_stats not found ...

  5. InnoDB: Error: Table &quot;mysql&quot;.&quot;innodb_table_stats&quot; not found.

    1,Mysqldump的时候报错例如以下: 2014-05-05 14:12:37 7f004a9a2700 InnoDB: Error: Table "mysql"." ...

  6. 使用vxe table组件时,edit-render配置$select',选中option后关闭cell的激活状态,显示选中option的value问题

    在我的项目中使用vxe table组件时,edit-render配置{name: '$select', options: [{label:"脉搏",value:"maib ...

  7. [转]File Descriptor泄漏导致Crash: Too many open files

    在实际的Android开发过程中,我们遇到了一些奇奇怪怪的Crash,通过sigaction再配合libcorkscrew以及一些第三方的Crash Reporter都捕获不到发生Crash的具体信息 ...

  8. @PathVariable出现点号"."时导致路径参数截断获取不全的解决办法

    @PathVariable出现点号"."时导致路径参数截断获取不全的解决办法 比如,我路径是/test/{name},name的值是1.2.3.4,后台用@PathVariable ...

  9. iOS -- xxxViewController进行pop时直接crash进main.m,EXC_BAD_ACCESS(code=1,address=0x20)

    今天在调试程序时,遇到了奇怪的错误.我从主页跳进(push)一个ViewController时一切正常,但是返回主页(pop)时却crash了,直接跳进了main.m(EXC_BAD_ACCESS(c ...

随机推荐

  1. CURL的使用<发送与接收数据>

    $headers = array( "TYPE:xxxxooooo", "TOKEN:00000000" ); $data = array( 'data' =& ...

  2. what is the virtual machine, when and why we need use it ?

    虚拟机(Virtual Machine)指通过软件模拟的具有完整硬件系统功能的.运行在一个完全隔离环境中的完整计算机系统. 通过虚拟机软件,你可以在一台物理计算机上模拟出二台或多台虚拟的计算机,这些虚 ...

  3. 获取股票历史数据和当前数据的API

    关键字:股票,stock,API,接口 1.获取股票当前数据 新浪数据接口:http://hq.sinajs.cn/list={code}.{code}替换为股票代码,沪市股票代码加前缀sh,深市股票 ...

  4. 解决 ListView 水平滚动条不出现的问题(转载)

    问题的原因:http://www.cnblogs.com/nankezhishi/archive/2010/03/17/wpfbug13.html 解决方法:http://www.cnblogs.co ...

  5. PHP数组的操作

    一.数组操作的基本函数数组的键名和值array_values($arr);获得数组的值array_keys($arr);获得数组的键名array_flip($arr);数组中的值与键名互换(如果有重复 ...

  6. maven添加jar包依赖

    maven的东西使用了一段时间,但是每次使用都多少有点含糊,所以总结一下. 目前主要使用是在jar包的控制上 原理: 在本地,指定一个文件夹,便是maven的仓库,maven会从远程的中央仓库中下载你 ...

  7. PAT-乙级-1006. 换个格式输出整数 (15)

    1006. 换个格式输出整数 (15) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 让我们用字母B来表示“百” ...

  8. The7th Zhejiang Provincial Collegiate Programming Contest->Problem A:A - Who is Older?

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3322 可以看样例猜题意的水题. #include<bits/stdc ...

  9. IOS 录像软件

    http://iphone.91.com/tutorial/cjjc/140430/21683219.html

  10. Tiny6410 交叉编译helloworld程序

    在工作目录下建立helloworld.c文件 #include <stdio.h> main() { printf("helloworld!\n"); } 保存关闭后. ...