Innodb parent table open时导致crash

case描述:

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

分析过程:

  case 用例:

CREATE TABLE `t1` (
  `f1` int(11) NOT NULL,
  PRIMARY KEY (`f1`)
) ENGINE=InnoDB

 CREATE TABLE `fk_1` (
  `f1` int(11) NOT NULL,
  PRIMARY KEY (`f1`),
  CONSTRAINT `pc1` FOREIGN KEY (`f1`) REFERENCES `t1` (`f1`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB
......

这里建了fk_[0-10000]张表。

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

时间: 2024-11-06 03:32:43

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

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"."innodb_table_stats" not found. 但是show tables我看这个表示存在的: 但是show create table innodb_index_stats;报错如下: mysql> show create table innodb_index_stats; ERRO

InnoDB: Error: Table &quot;mysql&quot;.&quot;innodb_table_stats&quot; not found索引表没找到,主从停止

InnoDB: Error: Table "mysql"."innodb_table_stats" not found. 导致:Seconds_Behind_Master: 27360  mysql主从同步停止 stop slave; 会一直卡住,service mysqld restart后,马上又会停止同步,出现同样问题. 初步判断: 因为innodb_table_stats表丢失,导致主从同步出现问题. 解决办法: 新建innodb_index_stats/i

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

问题现象:定义了DOCTYPE的页面 当表格的内容比div的高度还要高时,div会出现滚动条,同时在IE6和IE7下会出现问题: IE6:此时table的100%宽度还是没有滚动条那是的宽度,出现滚动条后,div的可视宽度减少,导致横向滚动条也出现了,而且横向能滚动的长度正好是滚动条的宽度. IE7:竖滚动条此时则很操蛋的消失了..... IE8:下一切正常. 解决方法:内嵌套一个分区元素 Layout <div style="width:100px; height=50px; overf

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

0x00 前言 在这篇文章中,我们选择了过去一周Unity官方社区交流群中比较有代表性的几个问题,总结在这里和大家进行分享.主要涵盖了IL2CPP.Scripting.Virtual Reality.Graphics.Editor.Terrain.Plugins .Education等领域,其中会着重介绍一下在原生的地形系统中使用ASTC格式纹理导致Crash的问题. 在文章结尾处我们还总结了社区小伙伴们过去一周在群里分享的一些干货连接. 同时,也欢迎大家加入我们这个讨论干货的官方技术群,交流看

MySQL 5.6 解决InnoDB: Error: Table &quot;mysql&quot;.&quot;innodb_table_stats&quot; not found.问题

在安装MySQL 5.6.30时,安装完成后,后台日志报如下警告信息:2016-05-27 12:25:27 7fabf86f7700 InnoDB: Error: Table "mysql"."innodb_table_stats" not found.2016-05-27 12:25:27 7fabf86f7700 InnoDB: Error: Fetch of persistent statistics requested for table "hj

【翻译自mos文章】在使用Linux大页内存的配置中,使用drop_cache时导致的ORA-600 [KGHLKREM1]问题

在使用Linux大页内存的配置中,使用drop_cache时导致的ORA-600 [KGHLKREM1]问题 来源于: ORA-600 [KGHLKREM1] On Linux Using Parameter drop_cache On hugepages Configuration (文档 ID 1070812.1) 适用于: Oracle Database - Enterprise Edition - Version 10.2.0.1 and later Generic Linux ***C

解决Qt中QTableWidget类方法setItem 时导致程序崩溃问题

在为一个音乐播放器增加功能时莫明奇妙的出现程序崩溃,定位到是由于QTableWidget 的setItem方法导致的,最终在此处找到了解决方式. 大致是说不能在setItem之前连接cellChanged 信号,把连接cellChanged信号的语句放置在一连串的setItem(在表格插入一行后调用的)之后就可以了. 解决Qt中QTableWidget类方法setItem 时导致程序崩溃问题

Mysql innodb错误解决 InnoDB: Error: table `mysql`.`innodb_table_stats`

通过ELK监控发现,程序连接mysql DB 失败,通过看程序的log和mysql的error log发现mysql中出现error 查看Mysql日志 发现 InnoDB: Error: table `mysql`.`innodb_table_stats` does not exist in the InnoDB internal 这个原因很明显 ,是mysql库的innodb_table_stats表损坏了. 首先登录mysql查看表是否存在?   结果:存在的. Tables_in_mys

Android 解决ListView在使用多个布局的同时使用convertView进行缓存时导致ListView下面有空白的问题

在使用ListView时,在Adapter里面使用convertView会提高ListView的性能,提升100%?但今天发现在listView同时加载不同的View的同时会导致ListView最底下有一块空白,可能是恰巧吧,导致这样的原因可能是加载了几个不同的View,而他们的高度不同,数量也不同,系统无法准确计算ListView的总高度. 在 BaseAdapter里面提供了两个回调函数来指定有多少种布局,指定position对应的是哪一个布局. @Override public int g