MySQL information_schema表查询导致内存暴涨

case:下面的一条sql语句,导致mysql实例内存暴涨:

  select * from tables where table_name not in(select table_name from partitions group by table_name having count(*)>1 );

  mysql 5.5, 1w+的innodb表。

下面看下调查的结果:

1.  sql的执行情况以及内存分配:

 

step1: 构造information_schema.tables临时表

1.1  构造临时表tables结构:

说明:func=create_schema_table; engine=heap

内存: tables是heap引擎的表,临时构造,使用堆内存;语句结束close_tmp_tables释放。

1.2 填充临时表tables数据:一共由三类表来填充tables的内存

  1. memory引擎:

说明:information_schema下的表,创建临时table,

内存: 使用堆内存,填充完数据后 close_tmp_tables,释放内存。

  2. mysiam引擎:

说明:information_schema下一部分表,是mysiam引擎的临时表。

内存: 使用堆内存,创建磁盘临时文件,close_tmp_tables,释放内存,删除临时文件。

3. innodb引擎和其它:

说明:使用正常的open_tables函数,创建table,table_share, handler对象。

内存: 使用堆内存

 

step2:构造information_schema.partition临时表

  步骤和step1一样,但partition因为blob的原因,系统创建的时候,指定了mysiam引擎的临时表,而非内存heap临时表。

如下图:

   

 

 2.  构造两张临时表的开销:

实例一共1w张表,加上系统表,大约10200张,为了构造这两个临时表:

a)  一共open了大约 10200*2 次,加上创建临时表,临时磁盘文件。

b)  而table_cache设置的400,所以opened_table基本没有复用,打开后马上关闭了。

两张并不存在的临时表,全部构造完成,以上为了构造临时表而open大量表所使用的堆内存,现在已经释放。

 

3.  下面可以执行sql

sql的执行计划是:

1   information_schema.tables

n   nest loops information_schema.partitions

nest loop即:对于tables每一条记录要扫描一次patitions。

 

4.  关键的问题是:

 

执行计划调用如下函数栈:

  mysql_select

   JOIN::exec

    do_select

      sub_select

      evaluate_join_record

        Item_subselect::exec

         subselect_single_select_engine::exec

          JOIN::exec

   

在JOIN::exec有以下的判断:

     if (table_list->schema_table_state && is_subselect)
      {
        table_list->table->file->extra(HA_EXTRA_NO_CACHE);
        table_list->table->file->extra(HA_EXTRA_RESET_STATE);
        table_list->table->file->ha_delete_all_rows();
        free_io_cache(table_list->table);
        filesort_free_buffers(table_list->table,1);
        table_list->table->null_row= 0;
      }
      else
        table_list->table->file->stats.records= 0;
      if (do_fill_table(thd, table_list, tab))
      {

即: subselect子查询如果是schema_table, 并且在执行状态中, 需要全部删除 partition里的数据,每次nest loop都重新do_fill_table。

 

执行的结果就是:

a)  为了构造两个临时表,open了10200*2次表,

b)  又为了每次nest loop,删除并构造了10200次partition表,一共open了10200*10200次表。

table_cache可以完全无视了。

 

 

但为什么会占用大量的内存?

 

在整个构造的过程中:

1. 堆内存 : 在open所有表后,往临时表填充完数据,就free了,不用等语句结束。

2. 线程内存: 为了构造字段,table list这些,内存都是从thd->mem_root线程中分配的,需要等语句结束才释放。

 

如下,每次子查询执行一次,thd->mem_root增加的memory block;

gdb) p *(this->thd->mem_root)
$4 = { min_malloc = 32, block_size = 8160, block_num = 748, first_block_usage = 0,

Breakpoint 1, JOIN::exec (this=0x7f9a2c01f508) at sql/sql_select.cc:1843
(gdb) p *(this->thd->mem_root)
$5 = { min_malloc = 32, block_size = 8160, block_num = 758, first_block_usage = 0,

Breakpoint 1, JOIN::exec (this=0x7f9a2c01f508) at sql/sql_select.cc:1843
(gdb) p *(this->thd->mem_root)
$6 = {f min_malloc = 32, block_size = 8160, block_num = 767, first_block_usage = 0,

所以:这个sql,因为open太多表,执行时间过长, 而thd内存因为语句没有结束,无法释放,内存一直往上涨, 等语句结束,thd->mem_root的内存全部通过free释放掉。

MySQL information_schema表查询导致内存暴涨

时间: 2024-10-14 18:46:31

MySQL information_schema表查询导致内存暴涨的相关文章

记一次mysql多表查询(left jion)优化案例

一次mysql多表查询(left jion)优化案例 在新上线的供需模块中,发现某一个查询按钮点击后,出不来结果,找到该按钮对应sql手动执行,发现需要20-30秒才能出结果,所以服务端程序判断超时,故先不显示结果 以下是对这条查询的优化记录 1 数据库配置 数据库配置:4C8G 主表数据:3W+ 2 sql语句 提取sql语句,简化如下 SELECT taba.id, taba.title, taba.type, taba.end_time, tabb.username, tabc.orgna

python3 mysql 多表查询

python3 mysql 多表查询 一.准备表 创建二张表: company.employee company.department #建表 create table department( id int, name varchar(20) ); create table employee( id int primary key auto_increment, name varchar(20), sex enum('male','female') not null default 'male'

MySQL多表查询回顾

----------------------siwuxie095 MySQL 多表查询回顾 以客户和联系人为例(一对多) 1.内连接 /*内连接写法一*/ select * from t_customer c,t_linkman l where c.cid=l.clid /*内连接写法二(inner 可以省略不写)*/ select * from t_customer c inner join t_linkman l on c.cid=l.clid 2.左外连接 /*左外连接(outer 可以省

mysql多表查询方法(left join(左连接),right join (右连接),inner join (内连接)的区别)

表A记录如下:  aID aNum  1 a20050111  2 a20050112  3 a20050113  4 a20050114  5 a20050115  表B记录如下:  bID bName  1 2006032401  2 2006032402  3 2006032403  4 2006032404  8 2006032408  创建这两个表SQL语句如下:  CREATE TABLE a  aID int( 1 ) AUTO_INCREMENT PRIMARY KEY ,  a

MYSQL 连表查询及别名用法

MYSQL连表查询是两个表之间的查询或者更多表之间查询,通过外键的方式查询所有的数据,在查询过程中产生字段的重复,为了区分这种情况数据库设计别名,有的表很长,也可以用别名. 1,连表查询 INNER JOIN ,LEFT JOIN,RIGHT JOIN INNER JOIN(内连接,或等值连接):获取两个表中字段匹配关系的记录.LEFT JOIN(左连接):获取左表所有记录,即使右表没有对应匹配的记录.RIGHT JOIN(右连接): 与 LEFT JOIN 相反,用于获取右表所有记录,即使左表

4 - MySQL:多表查询

MySQL:多表查询 一,介绍 本节主题 多表连接查询 复合条件连接查询 子查询 准备工作 #建表 create table department( id int, name varchar(20) ); create table employee( id int primary key auto_increment, name varchar(20), sex enum('male','female') not null default 'male', age int, dep_id int

python开发mysql:单表查询&多表查询

一 单表查询,以下是表内容 1 一 having 过滤 2 1.1 having和where 3 select * from emp where id > 15; 4 解析过程;from > where 找到数据 > 分组(没有默认一个组)> select 打印 where是出结果之前 5 select * from emp having id > 15; 6 解析过程;from > where 找到数据(没有约束条件,就是整个表)) > 分组(没有默认一个组)&

133 MySQL单表查询

目录 一.单表查询 1.1 语法 1.2 关键字优先级 1.3 注意(重点) 1.4 测试一个单表的distinct去重 二.表记录查询测试 2.1常用函数 2.2 数据准备 2.3 表记录测试 2.3.1 where条件查询 2.3.2 group by 分组查询 2.3.3 having 和 where 2.3.4 排序 order by 2.3.5 limit限制 一.单表查询 1.1 语法 每次查询出来的一些记录,他们都是一张表,只不过这张表是存在内存中的 查询记录如果想要二次利用的话,

mysql联表查询,使用phpStudy自带的

一.内联结.外联结.左联结.右联结的含义及区别在SQL标准中规划的(Join)联结大致分为下面四种:1.内联结:将两个表中存在联结关系的字段符合联结关系的那些记录形成记录集的联结.2.外联结:分为外左联结和外右联结.左联结A.B表的意思就是将表A中的全部记录和表B中联结的字段与表A的联结字段符合联结条件的那些记录形成的记录集的联结,这里注意的是最后出来的记录集会包括表A的全部记录.右联结A.B表的结果和左联结B.A的结果是一样的,最后出来的记录集会包括表B的全部记录.具体如下: Select l