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. 浏览器的visibilitychange 事件ie10以下不兼容

    方法1, <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...

  2. php提取淘宝URL中ID的代码

    一段可以提取淘宝URL中ID的PHP代码. 例如: <?php $taobao = 'taobao.com'; $tmall = 'tmall.com'; $guojitmall = 'tmal ...

  3. Python遍历文件夹枚举所有文件类型

    >>> import os >>> def enumfiles(path, dest): files = os.listdir(path) for f in fil ...

  4. Django Admin后台使用tinymc 富文本编辑器

    1.CDN地址 <script src="//cdn.tinymce.com/4/tinymce.min.js"></script> 2.修改base.ht ...

  5. MyEclipse新建Maven工程

    1.File-->New-->Web Project 2.新建文件夹 需要新建4个源文件夹,分别是  src/main/java   src/main/resources   src/te ...

  6. easy ui window 相关属性

    <div class="easyui-window" title="提示" style="width:550px;height:500px;pa ...

  7. 【学习总结】【多线程】 线程 & 进程 & NSThread(多线程的一套API)

    一.进程和线程 1.什么是进程 进程是指在系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内 比如同时打开 Chrome.Xcode,系统就会分别启动2个进 ...

  8. ORA-01034:oracle不可用 的解决方法

    晚上打开SQLPlus输入用户名和密码老是登不了,出现如上一行代码 "ORA-01034:ORACLE不可用"的错误 解决思路: 1.检查服务是否启动, 2.如果已经启动,说明数据 ...

  9. C# DateTime和DateTime?格式化时间

    DateTime: <%= Model.CreateTime.ToString("yyyy年MM月dd日 H时m分s秒")%>   DateTime?: <%= ...

  10. GIS的数学基础

    在这里需要说明一点,任何领域的概念.技术都有其特定的适用范围,有其解决的问题,有其发展的历史,所以,抛开应用环境.范围来谈技术就像是没有根系的枝丫,枝丫再粗壮也只是一根木头而已. 那接下来我们来聊聊什 ...