解析在OceanBase创建分区的常见问题|OceanBase 用户问题精粹

在《分区策略和管理分区计划的实践方案》这篇文章中,我们介绍了在ODC中制定分区策略及有效管理分区计划的经验。有不少用户在该帖下提出了使用中的问题,其中一个关于创建分区的限制条件的问题,也是很多用户遭遇的老问题。因此本文以其为切入,将创建分区的几个问题进行解析,与大家共同探讨分享。

为什么主键必须包含全部分区键?

用户问:“有一张订单流水表,数据很大,想考虑按年份对数据进行分区。现在只有 ID 列是主键。尝试了一下好像无法按日期进行分区。是必须要把日期做成和 ID 的联合主键才可以分区么?”

答案是对的,主键必须包含所有分区键。因为主键的唯一性检查是在各个分区内部进行的,如果主键不包含全部分区键,这个检查就会失效,所以 MySQL 及其他数据库,也一样会有这个要求。

-- 如果主键不包含全部分区键,建表就会失败报错,报错信息也挺明确的。
create table t1(c1 int, c2 int,c3 int,primary key (c1))
partition by range (c2) (partition p1 values less than(3),partition p1 values less than(6));ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function

下面举个例子:

create table t1(c1 int, c2 int,c3 int,primary key (c1, c2))
partition by range (c2) (partition p0 values less than(3),partition p1 values less than(6));
Query OK, 0 rows affected (0.146 sec)obclient [test]> insert into t1 values(1, 2, 3);
Query OK, 1 row affected (0.032 sec)obclient [test]> insert into t1 values(1, 5, 3);
Query OK, 1 row affected (0.032 sec)obclient [test]> select * from t1;
+----+----+------+
| c1 | c2 | c3   |
+----+----+------+
|  1 |  2 |    3 |
|  1 |  5 |    3 |
+----+----+------+
2 rows in set (0.032 sec)

我们创建了一张表,主键是 c1 和 c2,分区键是 c2,小于 3 的值在 p0 分区,大于等于 3 且小于 6 的值在 p1 分区。然后插入了两个行,第一行在 p0 分区,第二行在 p1 分区。

obclient [test]> select * from t1 PARTITION(p0);
+----+----+------+
| c1 | c2 | c3   |
+----+----+------+
|  1 |  2 |    3 |
+----+----+------+
1 row in set (0.033 sec)obclient [test]> select * from t1 PARTITION(p1);
+----+----+------+
| c1 | c2 | c3   |
+----+----+------+
|  1 |  5 |    3 |
+----+----+------+
1 row in set (0.034 sec)

如果主键只有 c1 而没有 c2,那么在 p0 和 p1 分区内对 c1 列的唯一性检测都会成功,因为在各个分区内 c1 列的值都不重复,然后就会判定插入的数据符合主键约束。但实际上在分区间会有重复值,数据并不符合主键约束,所以所有数据库在分区时,都要求主键包含全部分区键。

为什么分区能让查询变快?

用户另外一个问题:“按日期分区是否能达到让查询变快的目的?”

个人理解,分区除了可以让一张超级大表的数据比较被均衡地被负载在不同的数据库节点上,另外一个目的就是加速查询。因为查询时会利用过滤条件里面的分区键进行分区裁剪。例如下面这两个例子:

如果过滤条件里有分区键,计划中可以看到 partitions(p0),说明只扫描了 p0 这一个分区的数据。


obclient [test]> explain select * from t1 where c2 = 1;
+------------------------------------------------------------------------------------+
| Query Plan                                                                         |
+------------------------------------------------------------------------------------+
| ===============================================                                    |
| |ID|OPERATOR       |NAME|EST.ROWS|EST.TIME(us)|                                    |
| -----------------------------------------------                                    |
| |0 |TABLE FULL SCAN|t1  |1       |3           |                                    |
| ===============================================                                    |
| Outputs & filters:                                                                 |
| -------------------------------------                                              |
|   0 - output([t1.c1], [t1.c2], [t1.c3]), filter([t1.c2 = 1]), rowset=16            |
|       access([t1.c1], [t1.c2], [t1.c3]), partitions(p0)                            |
|       is_index_back=false, is_global_index=false, filter_before_indexback[false],  |
|       range_key([t1.c1], [t1.c2]), range(MIN,MIN ; MAX,MAX)always true             |
+------------------------------------------------------------------------------------+
11 rows in set (0.034 sec)

如果过滤条件里没有分区键,计划中可以看到 partitions(p[0-1]),说明扫描了 p0 和 p1 全部所有分区的数据。其中 PX PARTITION ITERATOR 算子就是用来循环扫描所有分区的迭代器。

obclient [test]> explain select * from t1 where c3 = 1;
+------------------------------------------------------------------------------------+
| Query Plan                                                                         |
+------------------------------------------------------------------------------------+
| =============================================================                      |
| |ID|OPERATOR                 |NAME    |EST.ROWS|EST.TIME(us)|                      |
| -------------------------------------------------------------                      |
| |0 |PX COORDINATOR           |        |1       |6           |                      |
| |1 |└─EXCHANGE OUT DISTR     |:EX10000|1       |6           |                      |
| |2 |  └─PX PARTITION ITERATOR|        |1       |5           |                      |
| |3 |    └─TABLE FULL SCAN    |t1      |1       |5           |                      |
| =============================================================                      |
| Outputs & filters:                                                                 |
| -------------------------------------                                              |
|   0 - output([INTERNAL_FUNCTION(t1.c1, t1.c2, t1.c3)]), filter(nil), rowset=16     |
|   1 - output([INTERNAL_FUNCTION(t1.c1, t1.c2, t1.c3)]), filter(nil), rowset=16     |
|       dop=1                                                                        |
|   2 - output([t1.c1], [t1.c2], [t1.c3]), filter(nil), rowset=16                    |
|       force partition granule                                                      |
|   3 - output([t1.c1], [t1.c2], [t1.c3]), filter([t1.c3 = 1]), rowset=16            |
|       access([t1.c1], [t1.c2], [t1.c3]), partitions(p[0-1])                        |
|       is_index_back=false, is_global_index=false, filter_before_indexback[false],  |
|       range_key([t1.c1], [t1.c2]), range(MIN,MIN ; MAX,MAX)always true             |
+------------------------------------------------------------------------------------+
19 rows in set (0.038 sec)

range 分区不支持 datetime 类型咋办?

用户的另另外一个问题:“range 分区不支持 datetime 类型咋办?”。

CREATE TABLE ff01 (a datetime , b timestamp)
PARTITION BY RANGE(UNIX_TIMESTAMP(a))(PARTITION p0 VALUES less than (UNIX_TIMESTAMP('2000-2-3 00:00:00')),PARTITION p1 VALUES less than (UNIX_TIMESTAMP('2001-2-3 00:00:00')),PARTITION pn VALUES less than MAXVALUE);ERROR 1486 (HY000): Constant or random or timezone-dependent expressions in (sub)partitioning function are not allowed

试了下,OB 的 MySQL 模式,为了兼容 MySQL 行为,会和 MySQL 对 random expressions 进行一些限制。我第一时间想到的是用生成列绕过,不过很快发现,为了兼容 MySQL 行为,OB 对生成列的使用也进行了限制,生成列里也不允许出现 UNIX_TIMESTAMP 这个特殊的表达式,所以并没什么卵用:

CREATE TABLE ff01 (a datetime , b timestamp as (UNIX_TIMESTAMP(a)))
PARTITION BY RANGE(b)(PARTITION p0 VALUES less than (UNIX_TIMESTAMP('2000-2-3 00:00:00')),PARTITION p1 VALUES less than (UNIX_TIMESTAMP('2001-2-3 00:00:00')),PARTITION pn VALUES less than MAXVALUE);ERROR 3102 (HY000): Expression of generated column contains a disallowed function

至于为啥 UNIX_TIMESTAMP 在生成列里属于 disallowed function,猜测大概率是因为它是个非 deterministic 的系统函数。非 deterministic 简单来说就是这个 UNIX_TIMESTAMP() 函数在前一秒执行,和在后一秒执行,可能会返回不同的结果。像分区表达式、生成列表达式、check 约束里面的表达式,都不允许出现这种非确定性的函数。

下面举个简单的例子,解释一下上面 ERROR 1486 这个报错里 random 一词,以及非 deterministic 的含义:

obclient [test]> select UNIX_TIMESTAMP();
+------------------+
| UNIX_TIMESTAMP() |
+------------------+
|       1725008180 |
+------------------+
1 row in set (0.042 sec)obclient [test]> select UNIX_TIMESTAMP();
+------------------+
| UNIX_TIMESTAMP() |
+------------------+
|       1725008419 |
+------------------+
1 row in set (0.041 sec)-- 是不是一下子就明白,为啥 UNIX_TIMESTAMP 这么特殊,在哪里都不受待见了吧?

不过不得不说,OB 的 MySQL 兼容性做的还挺好的,不仅是兼容了 MySQL 各种使用上的限制,甚至是一些 MySQL 的 bug 都给兼容了,虽然给使用带来了一些不便,不过迁移 MySQL 大概会变得比较轻松。

扯远了,回归正题,后面查了下 OB 官网,发现有一种分区方式叫 Range Columns,和 Range 分区十分类似,优点是相比 Range 分区可以支持更多的数据类型,例如用户需要的 datetime 类型,缺点是分区定义不支持表达式。

因为 Range 不支持 UNIX_TIMESTAMP 这类特殊的非 deterministic 表达式,所以个人理解这里可以通过 Range Columns 解决用户的问题。例如:

CREATE TABLE ff01 (a datetime , b timestamp)
PARTITION BY RANGE COLUMNS(a)(PARTITION p0 VALUES less than ('2023-01-01'),PARTITION p1 VALUES less than ('2023-01-02'),PARTITION pn VALUES less than MAXVALUE);Query OK, 0 rows affected (0.101 sec)

说来惭愧,我之前也一直没注意过 Range 分区和 Range Columns 分区的区别,一直是把他们等价的,今天也算是学习到了,哈哈~

最后附上一个 MySQL 的官网文档链接,感觉它对 RANGE COLUMNS partitioning 的介绍比 OB 的官网要更清楚些,在这里推荐给对分区方式感兴趣的朋友阅读~

1725007840

What else?

   有同学提出还可以通过利用 to_days 函数代替 UNIX_TIMESTAMP 函数的方式解决第三个问题,这样就不需要更改 range 分区为 range columns 分区了。例如:

##创建range分区表
-- 分区字段是start_time,类型datetime
CREATE TABLE dba_test_range_1 (id bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',`name` varchar(50) NOT NULL COMMENT 'name',start_time datetime NOT NULL COMMENT '开始时间',
PRIMARY KEY (id,start_time)
)AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4 COMMENT = 'test range' 
PARTITION BY RANGE(to_days(start_time))(PARTITION M202301 VALUES LESS THAN(to_days('2023-02-01')),PARTITION M202302 VALUES LESS THAN(to_days('2023-03-01')),PARTITION M202303 VALUES LESS THAN(to_days('2023-04-01')));

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/494460.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

重温设计模式--命令模式

文章目录 命令模式的详细介绍C 代码示例C代码示例2 命令模式的详细介绍 定义与概念 命令模式属于行为型设计模式,它旨在将一个请求封装成一个对象,从而让你可以用不同的请求对客户端进行参数化,将请求的发送者和接收者解耦,并且能…

NavMeshAgent直接transform.position移动报错

对于NavMeshAgent组件,如果直接用transform.position移动位置会报错如下: xxx can only be called on an active agent that has been placed on a NavMesh。 需要使用如下方法进行移动位置,先不激活,移动完毕再激活。 using Sy…

272-1路万兆光纤SFP+和1路千兆网络 FMC子卡模块

一、概述 该板卡是基于kc705和ml605的fmc 10g万兆光纤扩展板设计,提供了1路万兆光纤SFP和1路千兆网络接口。可搭配我公司开发的FPGA载卡使用。载卡可参考:ID204 SFP(10 Gigabit Small Form Factor Pluggable)是一种可…

GitCode 光引计划投稿|JavaVision:引领全能视觉智能识别新纪元

在人工智能技术飞速发展的今天,计算机视觉作为AI领域的重要分支,正逐渐渗透到各行各业中。JavaVision,作为[光引计划]的一部分,致力于提供一个基于Java的全能视觉智能识别解决方案。同时它集成了MilvusPlus,旨在提供一…

如何在自己的云服务器上部署mysql

如何在自己的云服务器上部署mysql 前言: 我是用的是阿里云服务器,我的服务器上安装的系统是Ubuntu 20.04,一下内容都是居于此撰写。 前期准备工作 远程链接自己的云服务器,这里给大家推荐一个好用的软件:FinalShel…

华院计算参与项目再次被《新闻联播》报道

12月17日,央视《新闻联播》播出我国推进乡村振兴取得积极进展。其中,华院计算参与的江西省防止返贫监测帮扶大数据系统被报道,该系统实现了由原来的“人找人”向“数据找人”的转变,有效提升监测帮扶及时性和有效性,守…

UML图【重要】

文章目录 2.1 类图概述2.2 类图的作用2.3 类图表示法2.3.1 类的表示方式2.3.2 类与类之间关系的表示方式2.3.2.1 关联关系2.3.2.2 聚合关系2.3.2.3 组合关系2.3.2.4 依赖关系2.3.2.5 继承关系2.3.2.6 实现关系 统一建模语言(Unified Modeling Language,U…

【数据科学导论】第一二章·大数据与数据表示与存储

🌈 个人主页:十二月的猫-CSDN博客 🔥 系列专栏: 🏀数据处理与分析_十二月的猫的博客-CSDN博客 💪🏻 十二月的寒冬阻挡不了春天的脚步,十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前言…

问题解决:发现Excel中的部分内容有问题。是否让我们尽量尝试恢复? 如果您信任此工作簿的源,请单击“是”。

在开发同步导出功能是遇到了如标题所示的问题,解决后遂记录下来供大家参考。 RestController public class XxxController {PostMapping("/export")public BaseResponse export(RequestBody PolicyErrorAnalysisExportReq exportReq, HttpServletRespons…

软件设计与体系结构

1.简要说明什么是软件体系结构,软件体系结构模型,为什么要建立软件体系结构模型? 答:软件体系结构指一个软件系统在高层次上的结构化组织方式,包括系统的组成部分和各个部分之间的关系,以及它们与环境之间的…

开发手札:CameraRTS精准性优化

虽然三维软件提供了基本的物体RTS操作,但是对于用户来说过于复杂。 这些操作方式需要用户理解什么是三维空间、XYZ坐标系、欧拉角等。但是用户视角下,就一个二维屏幕动来动去的鼠标光标。 之前写过一套RTM组件,RTM组件&#xff0…

高级的SQL查询技巧有哪些?

成长路上不孤单😊😊😊😊😊😊 【14后😊///C爱好者😊///持续分享所学😊///如有需要欢迎收藏转发///😊】 今日分享关于高级SQL查询技巧方面的相关内容&#xf…

helm的介绍和安装

1 helm概述 1.1 资源对象难以管理的问题 helm是k8s资源清单的管理工具,它就像Linux下的包管理器,比如centos的yum,ubuntu的apt helm:命令行工具,主要用于k8s的chart的创建,打包,发布和管理。…

专业的内外网数据交换方案 可解决安全、效率、便捷3大问题

内外网数据交换是很多企业和行业都会面临的场景,既然隔离了内外网,重中之重就是要确保数据的安全性,其次在数据流转交换过程中,不能太繁琐复杂,需要让用户快速、便捷的进行数据交换。首先我们来看看,在进行…

2024 楚慧杯 re wp

go_bytes 附件拖入ida 输入长度为0x28,每两位字符的4bit拼接 与一个常量值经过运算后的值进行异或,并且判断是否相等 脚本 bouquet 附件拖入ida。简单去一下花 构建了一个二叉树,然后递归调用函数 重新排列一下再层序遍历读出即可 zistel 附件…

BERT模型入门(1)BERT的基本概念

文章目录 BERT是Bidirectional Encoder Representations from Transformers的首字母简写,中文意思是:Transformer的双向编码器表示。它是谷歌发布的最先进的嵌入模型。BERT在许多NLP任务中提供了更好的结果,如问答、文本生成、句子分类等&…

ECharts关系图-关系图11,附视频讲解与代码下载

引言: 关系图(或称网络图、关系网络图)在数据可视化中扮演着至关重要的角色。它们通过节点(代表实体,如人、物体、概念等)和边(代表实体之间的关系或连接)的形式,直观地…

java全栈day19--Web后端实战(java操作数据库3)

一、MyBatis 1.1介绍 前提引入: controller(控制层)作用:接受请求,响应数据 service(业务层)作用:负责具体的逻辑处理 dao(持久层)作用:数据访问层 一般的访问流程:浏览器发起请求过来,先…

Hmsc包开展群落数据联合物种分布模型分析通用流程(Pipelines)

HMSC(Hierarchical Species Distribution Models)是一种用于预测物种分布的统计模型。它在群落生态学中的应用广泛,可以帮助科学家研究物种在不同环境条件下的分布规律,以及预测物种在未来环境变化下的潜在分布范围。 举例来说&a…

PostgreSQL 的历史

title: PostgreSQL 的历史 date: 2024/12/23 updated: 2024/12/23 author: cmdragon excerpt: PostgreSQL 是一款功能强大且广泛使用的开源关系型数据库管理系统。其历史可以追溯到1986年,当时由加州大学伯克利分校的一个研究团队开发。文章将深入探讨 PostgreSQL 的起源、…