MySQL一次大量内存消耗的跟踪

异步冰川
• 阅读 480
  • GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源。
  • GreatSQL是MySQL的国产分支版本,使用上与MySQL一致。
  • 文章来源:GreatSQL社区原创

线上使用MySQL8.0.25的数据库,通过监控发现数据库在查询一个视图(80张表的union all)时内存和cpu均明显上升。

在8.0.25 MySQL Community Server官方版本测试发现:只能在视图上进行数据过滤,不能将视图上的过滤条件下推到视图内的表上进行数据过滤。8.0.29以后的版本已解决该问题。

MySQL视图访问原理

下面是在8.0.25 MySQL Community Server上做的测试

使用sysbench 构造4张1000000的表

 mysql> select count(*) from sbtest1;

+----------+
| count(*) |
+----------+
|  1000000 |
+----------+

1 row in set (1.44 sec)
mysql> show create table sbtest1;

| Table   | Create Table  | sbtest1 | 
CREATE TABLE `sbtest1` (

  `id` int NOT NULL AUTO_INCREMENT,

  `k` int NOT NULL DEFAULT '0',

  `c` char(120) COLLATE utf8mb4_0900_bin NOT NULL DEFAULT '',

  `pad` char(60) COLLATE utf8mb4_0900_bin NOT NULL DEFAULT '',

  PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=2000000 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin |

+---------+-----------------------------------------------------------------------------------
1 row in set (0.00 sec)

手工收集表统计信息

mysql> analyze table sbtest1,sbtest2 ,sbtest3,sbtest4;

+----------------+---------+----------+----------+
| Table          | Op      | Msg_type | Msg_text |
+----------------+---------+----------+----------+
| sbtest.sbtest1 | analyze | status   | OK       |
| sbtest.sbtest2 | analyze | status   | OK       |
| sbtest.sbtest3 | analyze | status   | OK       |
| sbtest.sbtest4 | analyze | status   | OK       |
+----------------+---------+----------+----------+

4 rows in set (0.17 sec)

创建视图

drop view view_sbtest1 ;

Create view view_sbtest1  as 

select * from sbtest1 
union all 
select * from sbtest2 
union all 
select * from sbtest3 
union all 
select * from sbtest4;

查询视图

Select * from view_sbtest1 where id=1;

 mysql> Select id ,k,left(c,20) from view_sbtest1 where id=1;
+----+--------+----------------------+
| id | k      | left(c,20)           |
+----+--------+----------------------+
|  1 | 434041 | 61753673565-14739672 |
|  1 | 501130 | 64733237507-56788752 |
|  1 | 501462 | 68487932199-96439406 |
|  1 | 503019 | 18034632456-32298647 |
+----+--------+----------------------+
4 rows in set (1 min 8.96 sec)

通过主键查询数据, 查询返回4条数据,耗时1分8.96秒

查看执行计划

从执行计划上看,先对视图内的表进行全表扫描,最后在视图上过滤数据。

mysql> explain Select id ,k,left(c,20) from view_sbtest1 where id=1;
+----+-------------+------------+------------+------+---------------+-------------+---------+-------+--------+----------+-------+
| id | select_type | table      | partitions | type | possible_keys | key         | key_len | ref   | rows   | filtered | Extra |
+----+-------------+------------+------------+------+---------------+-------------+---------+-------+--------+----------+-------+
|  1 | PRIMARY     | <derived2> | NULL       | ref  | <auto_key0>   | <auto_key0> | 4       | const |     10 |   100.00 | NULL  |
|  2 | DERIVED     | sbtest1    | NULL       | ALL  | NULL          | NULL        | NULL    | NULL  | 986400 |   100.00 | NULL  |
|  3 | UNION       | sbtest2    | NULL       | ALL  | NULL          | NULL        | NULL    | NULL  | 986400 |   100.00 | NULL  |
|  4 | UNION       | sbtest3    | NULL       | ALL  | NULL          | NULL        | NULL    | NULL  | 986400 |   100.00 | NULL  |
|  5 | UNION       | sbtest4    | NULL       | ALL  | NULL          | NULL        | NULL    | NULL  | 986400 |   100.00 | NULL  |
+----+-------------+------------+------------+------+---------------+-------------+---------+-------+--------+----------+-------+
5 rows in set, 1 warning (0.07 sec)  

添加hint后的执行计划

添加官方的 merge hint 进行视图合并(期望视图不作为一个整体,让where上的过滤条件能下推到视图中的表),不能改变sql执行计划,优化器需要先进行全表扫描在对结果集进行过滤。sql语句的执行时间基本不变

mysql> explain Select /*+  merge(t1) */ id ,k,left(c,20) from view_sbtest1 t1 where id=1;
+----+-------------+------------+------------+------+---------------+-------------+---------+-------+--------+----------+-------+
| id | select_type | table      | partitions | type | possible_keys | key         | key_len | ref   | rows   | filtered | Extra |
+----+-------------+------------+------------+------+---------------+-------------+---------+-------+--------+----------+-------+
|  1 | PRIMARY     | <derived2> | NULL       | ref  | <auto_key0>   | <auto_key0> | 4       | const |     10 |   100.00 | NULL  |
|  2 | DERIVED     | sbtest1    | NULL       | ALL  | NULL          | NULL        | NULL    | NULL  | 986400 |   100.00 | NULL  |
|  3 | UNION       | sbtest2    | NULL       | ALL  | NULL          | NULL        | NULL    | NULL  | 986400 |   100.00 | NULL  |
|  4 | UNION       | sbtest3    | NULL       | ALL  | NULL          | NULL        | NULL    | NULL  | 986400 |   100.00 | NULL  |
|  5 | UNION       | sbtest4    | NULL       | ALL  | NULL          | NULL        | NULL    | NULL  | 986400 |   100.00 | NULL  |
+----+-------------+------------+------------+------+---------------+-------------+---------+-------+--------+----------+-------+
5 rows in set, 1 warning (0.00 sec)

创建视图(过滤条件在视图内)

mysql> drop view view_sbtest3;
ERROR 1051 (42S02): Unknown table 'sbtest.view_sbtest3'
mysql> Create view view_sbtest3 as 
     select * from sbtest1 where id=1
      union all 
      select * from sbtest2 where id=1
     union all 
    select * from sbtest3  where id=1
     union all 
    select * from sbtest4 where id=1;
Query OK, 0 rows affected (0.02 sec)

查询视图(过滤条件在视图上)

Select id ,k,left(c,20) from view_sbtest3 where id=1;

mysql>  Select id ,k,left(c,20) from view_sbtest3 where id=1;
+----+--------+----------------------+
| id | k      | left(c,20)           |
+----+--------+----------------------+
|  1 | 501462 | 68487932199-96439406 |
|  1 | 434041 | 61753673565-14739672 |
|  1 | 501130 | 64733237507-56788752 |
|  1 | 503019 | 18034632456-32298647 |
+----+--------+----------------------+
4 rows in set (0.01 sec)

直接运行sql语句

 mysql> select id ,k,left(c,20) from sbtest1 where id=1  
    ->  union all 
    ->  select id ,k,left(c,20) from sbtest2 where id=1  
    ->  union all 
    ->  select id ,k,left(c,20) from sbtest3 where id=1 
    ->  union all 
    ->  select id ,k,left(c,20) from sbtest4 where id=1;
+----+--------+----------------------+
| id | k      | left(c,20)           |
+----+--------+----------------------+
|  1 | 501462 | 68487932199-96439406 |
|  1 | 434041 | 61753673565-14739672 |
|  1 | 501130 | 64733237507-56788752 |
|  1 | 503019 | 18034632456-32298647 |
+----+--------+----------------------+
4 rows in set (0.01 sec)

直接运行sql语句或者把过滤条件放到视图内均能很快得到数据。

8.0.32

新的MySQL8.0.32版本 已解决掉该问题,视图上的过滤条件能下推到表上。

 Server version: 8.0.32 MySQL Community Server - GPL

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use sbtest;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> Select id ,k,left(c,20) from view_sbtest1 where id=1;
+----+--------+----------------------+
| id | k      | left(c,20)           |
+----+--------+----------------------+
|  1 | 501462 | 68487932199-96439406 |
|  1 | 434041 | 61753673565-14739672 |
|  1 | 501130 | 64733237507-56788752 |
|  1 | 503019 | 18034632456-32298647 |
+----+--------+----------------------+
4 rows in set (0.01 sec)

mysql> Select id ,k,left(c,20) from view_sbtest3 where id=1;
+----+--------+----------------------+
| id | k      | left(c,20)           |
+----+--------+----------------------+
|  1 | 501462 | 68487932199-96439406 |
|  1 | 434041 | 61753673565-14739672 |
|  1 | 501130 | 64733237507-56788752 |
|  1 | 503019 | 18034632456-32298647 |
+----+--------+----------------------+
4 rows in set (0.00 sec)

Enjoy GreatSQL :)

## 关于 GreatSQL

GreatSQL是由万里数据库维护的MySQL分支,专注于提升MGR可靠性及性能,支持InnoDB并行查询特性,是适用于金融级应用的MySQL分支版本。

相关链接: GreatSQL社区 Gitee GitHub Bilibili

GreatSQL社区:

社区博客有奖征稿详情:https://greatsql.cn/thread-100-1-1.html

MySQL一次大量内存消耗的跟踪

技术交流群:

微信:扫码添加GreatSQL社区助手微信好友,发送验证信息加群

MySQL一次大量内存消耗的跟踪

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
Oracle与MySQL的SQL语句区别
Oracle与MySQL的SQL语句区别\注(来源于学习时的资料具体出处不明如有需求请联系备注转载链接或删除。)1数据库/\ mysql可以创建数据库,而oracle没有这个操作,oracle只能创建实例; sql数据库操作:database 格式:  \
Stella981 Stella981
3年前
Python3:sqlalchemy对mysql数据库操作,非sql语句
Python3:sqlalchemy对mysql数据库操作,非sql语句python3authorlizmdatetime2018020110:00:00coding:utf8'''
Wesley13 Wesley13
3年前
MySQL 修改数据表中的字段的字符编码
1、查询MySQL的版本:  SELECTVERSION();2、查询MySQL当前使用的字符集:  SHOWVARIABLESLIKE'%character%';3、查询指定数据库的指定数据表的状态信息(db_test是数据库,t_text是数据表):  SHOWTABLESTAT
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
MariaDB安装教程
MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可MariaDB的目的是完全兼容MySQL,包括API和命令行,使之能轻松成为MySQL的代替品。在存储引擎方面,使用XtraDB(英语:XtraDB)来代替MySQL的InnoDB。安装命令yumyinstallmariadbmariadbser
Wesley13 Wesley13
3年前
thinkphp 基本配置
12returnarray(34//定义数据库连接信息5'DB\_TYPE''mysql',//指定数据库是mysql67'DB\_HOST''localhost',89'DB\_NAME''uchome',//数据库名1011'DB\_USER''root
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Vitess全局唯一ID生成的实现方案 | 京东云技术团队
为了标识一段数据,通常我们会为其指定一个唯一id,比如利用MySQL数据库中的自增主键。但是当数据量非常大时,仅靠数据库的自增主键是远远不够的,并且对于分布式数据库只依赖MySQL的自增id无法满足全局唯一的需求。因此,产生了多种解决方案,如UUID,Sn
美凌格栋栋酱 美凌格栋栋酱
5个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(