MySQL的KEY分区存在BUG,请慎用

1. 问题现象

上个星期排查项目【此项目是一个外包项目,但数据查询慢】问题时,发现一个很奇怪的现象:

项目使用mysql 5.7,有几个频繁操作的表,使用mysql 的key 分区,分区数是10、100,建表语句类似如下:

CREATE TABLE `tbl_key_partition` (
  `id` varchar(64) NOT NULL COMMENT 'id',
  `updateTime` datetime DEFAULT NULL
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
PARTITION BY KEY ()
PARTITIONS 100 ;

奇数编号分区的ibd文件大小都是固定的,96k,这是创建分区表时初始化大小,实际并没有任何数据,可以通过

select partition_name, partition_expression, table_rows from information_schema.partitions where table_schema = schema() and table_name='tbl_key_partition' 

 select count(*) from tbl_key_partition partition(p91)

发现数据都分布在偶数编号的分区,奇数编号分区数据量为0

2. 问题重现

在mysql中创建tbl_key_partition表,然后使用load_data存储过程插入10万数据,存储过程的源码如下:

--定义存储过程
drop PROCEDURE if EXISTS load_data;
delimiter $$
CREATE PROCEDURE load_data (in num int) 
BEGIN
	DECLARE v INT DEFAULT 0;
	WHILE v < num DO
		INSERT INTO tbl_key_partition VALUES (concat(substring(md5(rand()),1,10),v), date_add('2020-01-01 00:00:00', interval v second) );
		SET v = v + 1;
	END WHILE;
END$$ 
delimiter ;

--调用存储过程
call load_data(100000)

查看表中各分区的数据量分布,如下图,数据基本上都写到了偶数编号的分区上,奇数编号的分区只写了极少数的数据。另外奇数编号分区的ibd文件大小都是固定为96K,所以重现了问题。

3. 原因分析

3.1 MySQL key 分区原理

KEY分区的原理:通过MySQL内置hash算法对分片键计算hash值后再对分区数取模,详见:https://dev.mysql.com/doc/refman/5.7/en/partitioning-key.html

按键分区与按哈希分区类似,不同的是,哈希分区使用用户定义的表达式,用于键分区的哈希函数由MySQL服务器提供。NDB集群使用MD5()来实现此目的;

对于使用其他存储引擎的表,服务器使用自己的内部散列函数,该函数基于与PASSWORD()相同的算法。

3.2 原因

使用 mysql key 分区 bug 作为关键字进行搜索,发现有不少内容描述此问题。比如这个 MySQL之KEY分区引发的血案。这个就是mysql 5.7的bug, 但官网却没有任何说明,

所以建议不要使用key分区 ,建议使用hash或范围分区

其他文章的结论如下:

  1. 根据password函数,分析并测出,key分区,只能指定分区数目为质数,才能保证每个分区都有数据。我测了下,从11个分区,到17个分区。 只有11,13,17 ,这3个分区的数据是基本平均分布的

  2. 如果设置40,64,128等偶数个分区数(PARTITIONS 64),会导致编号为奇数的分区(p1, p3, p5, p7, … p2n-1)完全插不进数据;

  3. 如果设置63,121(PARTITIONS 63)这种奇数但非质数个分区数,所有分区都会有数据,但是不均匀;

  4. 如果设置137,31这种质数个分区数(PARTITIONS 137),所有分区都会有数据,并且非常均匀;

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: MySQLKey 分区和 HASH 分区是两种不同的表分区方法。 Key 分区是根据分区键(也就是表中的某一列)的值来决定将行存储在哪个分区中。可以使用数值、日期或时间类型的列作为分区键。例如,可以将数据按照日期分区,将每个月的数据存储在一个分区中。 HASH 分区是根据分区键的哈希值来决定将行存储在哪个分区中。这种方法通常用于数据量较大的表,因为它可以将数据均匀地分布在各个分区中,减少碎片。但是,HASH 分区不能使用日期或时间类型的列作为分区键,也不能对分区进行范围查询。 总的来说,Key 分区更适用于日期或时间类型的数据,而 HASH 分区更适用于大量数据的情况,但是它不能进行范围查询。 ### 回答2: MySQL中的Key分区和HASH分区是两种不同的表分区方式。 Key分区是根据指定列的取值范围将表数据划分成若干分区。在创建表时,可以通过指定分区键来定义Key分区分区键可以是整数、日期等类型的列。Key分区的主要特点是可以根据指定的列值迅速定位到对应的分区,因此适合于范围查询。当新数据插入时,系统将根据分区键的取值范围决定将数据插入到哪个分区中。Key分区的缺点是分区键的选择非常重要,如果选择不当可能导致数据分布不均匀,进而影响查询性能。 HASH分区是根据指定列的哈希值将表数据划分成若干分区。在创建表时,可以通过指定分区键来定义HASH分区分区键可以是整数、字符串等类型的列。HASH分区的主要特点是可以将数据均匀地分布到各个分区中,因此适合于随机访问。当新数据插入时,系统将根据分区键的哈希值决定将数据插入到哪个分区中。HASH分区的缺点是无法支持范围查询,因为数据的分布是随机的,必须查询所有的分区才能得到完整的结果。 总的来说,Key分区适合于范围查询,HASH分区适合于随机访问。具体选择哪种分区方式要根据具体的业务需求和查询模式来决定。 ### 回答3: MySQL中的分区是将表分割为更小的、可管理的部分,以提高查询效率和管理性能。在MySQL中,Key分区和HASH分区是两种常见的分区方式。 首先,Key分区是基于表中的一个或多个列的值来进行分区的。它使用确定的算法将分区键的值映射到相应的分区中。这种分区方式适用于具有明确定义的范围或离散值的列,例如日期范围或状态值。Key分区可以使得查询只需要扫描特定的分区而不是整个表,提高查询性能。 而HASH分区是基于分区键的哈希值来进行分区的。它使用哈希算法将分区键的值转换为固定长度值,并根据这个值将数据分配到不同的分区中。这种分区方式适用于分区键的值分布比较均匀,且查询频率比较平衡的情况。HASH分区可以保证数据在各个分区均匀分布,避免数据倾斜的问题。 总结来说,Key分区是基于列的值范围或离散值进行分区的,适用于有明确定义范围的列;而HASH分区是基于哈希值进行分区的,适用于分区键分布较为均匀的情况。两者适用的场景有所差异,根据具体需求选择合适的分区方式可以提高查询效率和管理性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

enjoy编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值