我的编程空间,编程开发者的网络收藏夹
学习永远不晚

关于MySQL分区表的一个性能BUG

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

关于MySQL分区表的一个性能BUG

一、问题描述

最近遇到一个问题,也就是使用分区表进行数据查询/加载的时候比普通表的性能下降了约50%,主要瓶颈出现在CPU,既然是CPU瓶颈理所当然的我们可以采集perf top -a -gpstack来寻找性能瓶颈所在,同时和普通表进行对比,发现CPU主要耗在函数build_template_field上如下图:

二、使用pt-pmap进行栈分析

为了和perf top -g -a进行相互印证,我们同时获取了当时的pstack,由于线程较多为了方便获取有用的信息我们通过pt-pmap进行了格式化如下:

格式化后我们提出掉空闲的等待栈,发现大量的如上,这也和perf top -a -g中的表现进行了相互印证。

三、关于本列中瓶颈点的分析

我们看到这里大量的cpu耗在


ha_innobase::build_template
 ->build_template_field
   ->dict_col_get_clust_pos

对于template来讲,其几乎是和特定的一次的查询进行绑定的,也就是普通的语句至少需要一个template。其结构为row_prebuilt_t,包含查询元组,查询的表,查询用到的索引,事务相关信息,持久化游标,MySQL层查询行的长度,自增信息,ICP相关信息,mysql_row_templ_t结构等信息。其中mysql_row_templ_t 这个信息就是每个字段一个,主要作用记录的是MySQL层feild信息和Innodb层columns信息的相关属性,用于快速转换一行记录在MySQL层和Innodb层之间转换。为了初始化mysql_row_templ_t 就出现了上面的逻辑,

大概逻辑如下:

循环表中每个字段(一层循环)ha_innobase::build_template
  是否为需要访问的字段 build_template_needs_field
  这里包含查询和写入的所有字段,需要访问的字段越多越慢
   如果不是则不作继续循环
  如果需要访问
  build_template_field(mysql_row_templ_t结构体填充)
    循环主键的每个字段(二层循环)
    包含伪列,主键就是表的里面全部字段,表中字段越多越慢)dict_col_get_clust_pos  
      确认本字段在主键的位置
      pos0 主键 pos1 DB_TRX_ID pos2 DB_ROLL_PTR pos3 开始为用户其他字段
    循环索引的每个字段(二层循环,但是索引字段一般不会太多,因此这里不会慢)dict_index_t::get_col_pos
      确认本字段在索引的位置,如果没有则返回NULL
      返回pos 比如 主键 id1  二级索引 id2 id3 二级索引为 pos0 id2 pos1 id3 pos2 id1
    继续完成其他属性比如mysql null位图,mysql显示长度,mysql字符集等等

这里我们看到这里实际上有2层循环,也就是循环套循环(时间复杂度O(M×N)),而循环影响最大的有2个地方:

  • 第一层,表中字段的多少
  • 第二层,需要访问的字段(读和写都算)在主键(也就是全部字段)中循环

这里也就是为什么这里会慢的原因。但是template通常不会一个查询进行多次建立,比如一个普通表的大查询,只有在语句第一次进行数据定位之前会进行建立,这就不得不说这是分区表和普通表的对比中一个特殊的地方了。下面描述一下。

四、分区表中多次建立template的情况

假设我们有如下的分区表:


create table t(
    id1 int,
    id2 int,
    primary key(id1),
    key(id2)
)engine=innodb
partition by range(id1)(
    partition p0 values less than(100),
    partition p1 values less than(200),
    partition p2 values less than(300));    

insert into t values(1,1);
insert into t values(101,1);
insert into t values(201,1);
insert into t values(2,2);
insert into t values(3,2);
insert into t values(4,2);
insert into t values(7,2);
insert into t values(8,2);
insert into t values(9,2);
insert into t values(10,2);

我们使用语句"select * from t where id2=1",显然id2是二级索引,由于MySQL全部都是local分区的二级索引,因此这里值分别分布在3个分区中,对于这样一个语句在本该是普通表通过上次定位后的位置继续访问(next_same)的时候,通过封装分区表的方法,将其改为了index read再次定位,而我们可以清楚的看到这里是scan next partition,其part=1这是第二个分区了,也就是我们的p1(第一个为0)

这样template需要每个分区(scan next partition)都进行重建,这样就出现了我们上面的问题。这个其实也可以理解,新的分区是新的innodb文件,这样上次定位的持久化游标实际已经没有什么用了,就相当于一次新的表访问。这里在是否进行template建立还有一个判断如下:


  if (m_prebuilt->sql_stat_start) {
    build_template(false);
  }

而m_prebuilt->sql_stat_start除了在语句开始的时候设置为true,每次更换分区依旧会设置为true如下:


ha_innopart::set_partition:
m_prebuilt->sql_stat_start = m_sql_stat_start_parts.test(part_id);

五、关于一个特殊的流程

在我们的故障pstack中还有一个栈如下:

这个栈实际并不完整,但是其中出现了Partition_helper::handle_ordered_index_scan,这个函数实际上和分区表的排序有关,如果我们考虑这样一种情况,对于二级索引select max(id2) from t,那么需要首先访问每个分区获取其中的最大值然后对比每个分区的最大值,得到最终的结果,而MySQL则采用优先队列进行处理,这应该是就是本函数完成的部分功能(没仔细去看)。其次我们先出现了QUICK_RANGE_SELECT这是范围查询会用到的,那么我们构造如下:


select * from t where id2<2 order by id2;


栈:

这里就是因为id2这个字段只保证在分区内部是按照大小排列的但是在整个表来讲,它是无序的,需要额外的处理。

六、问题模拟

有了这些准备,我们可以构造一个300个字段和25个分区的分区表。测试版本最新8.0.26


create table tpar300col(
    id1 int,
    id2 int,
    id3 int,
    id4 int,
...
    id299 varchar(20),
    id300 varchar(20),
    primary key(id1),
    key(id2)
)engine=innodb
partition by range(id1)(
    partition p0 values less than(100),
    partition p1 values less than(200),
    partition p3 values less than(300),
 ...
    partition p25 values less than(2500));  

insert into tpar300col values(1  ,1,1,
....每个分区一条数据
insert into tpar300col values(2401,1,1

然后构造一些其他数据id2不要为1,建立存储过程:


delimiter //

CREATE PROCEDURE test300col()
begin 
  declare num int;
  set num = 1; 
while num <= 1000000 do
  select * from tpar300col where id2=1;
  set num = num+1;
end while;
end //
执行:
 /opt/mysql/mysql3340/install/mysql8/bin/mysql -S--socket=/opt/mysql/mgr3315/data/mgr3315.sock -e'use test;call test300col();' > log.log

然后perf top 观察如下:

这样问题就得到了确认。

七、总结

这个问题实际上和二级索引相对于分区键的数据离散度有关,但是我们无法控制二级索引的数据,并且索引也是必须使用的。只能通过一些方面尽量避免,当然我也提交了一个BUG,如下:

https://bugs.mysql.com/bug.php?id=104576

不知道是否有办法修复这个问题,比如对于分区表来讲实际上每个分区的字段都是一样的,是否需要每次都重建mysql_row_templ_t.clust_rec_field_no?如果不需要那么问题自解,官方目前已经验证了这个问题确实存在。如下是一些避免的方式,

  • 分区表字段不宜过多
  • 访问的字段不应该一味的使用select *
  • 避免使用hash分区,hash分区会增加这种问题

到此这篇关于讲诉MySQL分区表的一个性能BUG的文章就介绍到这了,更多相关MySQL分区表的一个性能BUG内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

关于MySQL分区表的一个性能BUG

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

PHP与MySQL索引的分区表和水平分表的设计策略及其对查询性能的影响

引言:在开发Web应用程序时,PHP与MySQL是经常使用的强大工具。在设计数据库结构时,索引的选择和使用对查询性能影响极大。本文将重点讨论索引的分区表和水平分表的设计策略以及对查询性能的影响,并提供具体的代码示例。一、索引的分区表设计策略
2023-10-21

如何设计一个高性能的MySQL表结构来实现推荐美食功能?

如何设计一个高性能的MySQL表结构来实现推荐美食功能?随着人们对美食的需求越来越高,推荐系统在美食领域的应用也逐渐增多。设计一个高性能的MySQL表结构来实现推荐美食功能,将会对提升用户体验和平台发展起到重要作用。本文将介绍如何设计这样一
如何设计一个高性能的MySQL表结构来实现推荐美食功能?
2023-10-31

如何设计一个高性能的MySQL表结构来实现日志管理功能?

如何设计一个高性能的MySQL表结构来实现日志管理功能?随着互联网的发展,日志管理对于系统运维和故障分析变得越来越重要。MySQL作为一种常用的关系型数据库,在日志管理中也发挥着重要作用。设计一个高性能的MySQL表结构来实现日志管理功能,
如何设计一个高性能的MySQL表结构来实现日志管理功能?
2023-10-31

如何设计一个高性能的MySQL表结构来实现推荐书籍功能?

如何设计一个高性能的MySQL表结构来实现推荐书籍功能?推荐系统在现代电商平台和社交媒体应用中起着至关重要的作用,能够提高用户体验、增加用户黏性和促进销售。而在推荐系统中,一个关键的部分就是基于用户的兴趣和行为数据来推荐相关的书籍。在设计高
如何设计一个高性能的MySQL表结构来实现推荐书籍功能?
2023-10-31

如何设计一个高性能的MySQL表结构来实现推荐影视功能?

如何设计一个高性能的MySQL表结构来实现推荐影视功能?在当前互联网时代,推荐系统已经成为了各大影视平台的一项重要功能。通过推荐系统,平台可以根据用户的兴趣和行为习惯,推荐他们可能感兴趣的影视作品,提高用户的使用体验和平台的收益。而推荐系统
如何设计一个高性能的MySQL表结构来实现推荐影视功能?
2023-10-31

如何设计一个高性能的MySQL表结构来实现推荐系统功能?

如何设计一个高性能的MySQL表结构来实现推荐系统功能?推荐系统是很多互联网平台的重要组成部分,它通过分析用户的行为和偏好,提供个性化的推荐内容。在推荐系统的实现中,数据库扮演着关键角色,因此设计一个高性能的MySQL表结构非常重要。本文将
如何设计一个高性能的MySQL表结构来实现推荐系统功能?
2023-10-31

如何设计一个高性能的MySQL表结构来实现推荐电影功能?

如何设计一个高性能的MySQL表结构来实现推荐电影功能?近年来,推荐系统在电商、社交网络、音乐和影视等领域得到了广泛应用。其中,推荐电影功能在视频流媒体平台上尤为重要。为了实现高性能的推荐电影功能,设计一个合理的MySQL表结构是至关重要的
如何设计一个高性能的MySQL表结构来实现推荐电影功能?
2023-10-31

如何设计一个高性能的MySQL表结构来实现地理位置功能?

如何设计一个高性能的MySQL表结构来实现地理位置功能?地理位置功能在许多应用程序中都是必不可少的,例如地图应用、附近的人、附近的商家等。在MySQL数据库中,我们可以通过合理设计表结构和使用索引来实现地理位置功能,并保证高性能的查询和更新
如何设计一个高性能的MySQL表结构来实现地理位置功能?
2023-10-31

如何设计一个高性能的MySQL表结构来实现推荐音乐功能?

如何设计一个高性能的MySQL表结构来实现推荐音乐功能?摘要:随着音乐流媒体服务的普及,推荐音乐功能是吸引用户的重要方式之一。在实现推荐音乐功能时,合理设计MySQL表结构对于提高性能至关重要。本文将详细介绍如何设计一个高性能的MySQL表
如何设计一个高性能的MySQL表结构来实现推荐音乐功能?
2023-10-31

如何设计一个高性能的MySQL表结构来实现推荐电视剧功能?

如何设计一个高性能的MySQL表结构来实现推荐电视剧功能?推荐系统在今天的电视剧平台中变得越来越重要,它不仅可以帮助用户发现新的电视剧,还可以提升用户体验。而一个高性能的MySQL表结构设计是实现这一目标的关键。本文将介绍如何设计一个高性能
如何设计一个高性能的MySQL表结构来实现推荐电视剧功能?
2023-10-31

如何设计一个灵活的MySQL表结构来实现问答社区功能?

如何设计一个灵活的MySQL表结构来实现问答社区功能?随着互联网的快速发展,问答社区成为了人们获取知识和交流经验的重要平台。要实现一个功能完善的问答社区,良好的数据库设计是至关重要的一步。MySQL是一个广泛使用的关系型数据库管理系统,本文
如何设计一个灵活的MySQL表结构来实现问答社区功能?
2023-10-31

如何设计一个可扩展的MySQL表结构来实现社区管理功能?

如何设计一个可扩展的MySQL表结构来实现社区管理功能?随着互联网的快速发展,社区类网站的兴起越来越多,为了实现一个高效且功能完善的社区管理系统,合理的MySQL表结构设计是至关重要的。本文将介绍一种可扩展的MySQL表结构设计方案,并提供
如何设计一个可扩展的MySQL表结构来实现社区管理功能?
2023-10-31

如何使用MySQL和Ruby实现一个简单的数据分析报表功能

如何使用MySQL和Ruby实现一个简单的数据分析报表功能引言:在当今数据驱动的时代,数据分析对于企业的决策和发展起到了至关重要的作用。而数据分析报表作为数据分析的重要组成部分,对于对数据进行整理、可视化和解读具有重要意义。本文将介绍如何使
2023-10-22

如何设计一个优化的MySQL表结构来实现数据分发功能?

如何设计一个优化的MySQL表结构来实现数据分发功能?在开发数据库应用程序的过程中,我们常常需要将数据分发到不同的表中,以满足在不同的业务场景下的需求。设计一个优化的MySQL表结构来实现数据分发功能,可以提高数据访问效率和查询性能,保证数
如何设计一个优化的MySQL表结构来实现数据分发功能?
2023-10-31

编程热搜

目录