解析在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.mzph.cn/web/63653.shtml

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

相关文章

有哪些免费的 ERP 软件可供选择?哪些 ERP 软件使用体验较好?

想找个 “免费” 的 ERP 软件? 咱得知道,ERP 那可是涉及财务、人力、供应链、采购、销售等好多方面的重要企业软件。功能这么全,能免费才怪呢!真要是有免费的,早就火遍大江南北,说不定把市场都垄断了&…

centos-stream9系统安装docker

如果之前安装过docker需要删除之前的。 sudo dnf -y remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine 安装yum-utils工具: dnf -y install yum-utils dnf-plugin…

了解cuda的统一内存

1. CUDA 6中的统一内存 在CUDA 6中,从Kepler GPU架构(计算能力3.0或更高)开始,在64位Windows 7、8和Linux操作系统(内核2.6.18)上开始支持统一内存. 从CUDA 6开始,NVIDIA推出了CUDA平台历史上…

Pytorch | 从零构建MobileNet对CIFAR10进行分类

Pytorch | 从零构建MobileNet对CIFAR10进行分类 CIFAR10数据集MobileNet设计理念网络结构技术优势应用领域 MobileNet结构代码详解结构代码代码详解DepthwiseSeparableConv 类初始化方法前向传播 forward 方法 MobileNet 类初始化方法前向传播 forward 方法 训练过程和测试结果…

Electronjs+Vue如何开发PC桌面客户端(Windows,Mac,Linux)

electronjs官网 https://www.electronjs.org/zh/ Electron开发PC桌面客户端的技术选型非常适合已经有web前端开发人员的团队。能够很丝滑的过渡。 Electron是什么? Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 Chromium 和 Node.…

【1.排序】

排序 笔记记录 1.排序的基本概念1.1 排序的定义 2. 插入排序2.1 直接插入排序2.2 折半插入排序2.3 希尔排序 3. 交换排序3.1 冒泡排序3.2 快速排序 4. 选择排序4.1 简单选择排序4.2 堆排序 5. 归并排序、基数排序和计数排序5.1 归并排序4.2 基数排序4.3 计数排序 6. 各种内部排…

Linux Swap: 深入解析 mkswap, mkfs.swap, 和 swapon

文章目录 Linux Swap: 深入解析 mkswap, mkfs.swap, 和 swapon什么是 Swap?主要命令介绍1. mkswap2. mkfs.swap3. swapon 创建和管理 Swap 的步骤1. 创建 Swap 分区2. 初始化 Swap3. 激活 Swap4. 持久化配置5. 查看 Swap 状态 删除 Swap 分区或文件1. 停用 Swap2. 删…

取子串(指针)

#include <stdio.h> #include <string.h>char* substr(char *s, int startloc, int len) {static char result[51]; // 定义一个足够大的静态数组来存储结果static char result1[] {N,U,L,L,\0};int i, j;// 检查startloc是否在字符串的范围内if (startloc < 1…

「Mac畅玩鸿蒙与硬件45」UI互动应用篇22 - 评分统计工具

本篇将带你实现一个评分统计工具&#xff0c;用户可以对多个选项进行评分。应用会实时更新每个选项的评分结果&#xff0c;并统计平均分。这一功能适合用于问卷调查或评分统计的场景。 关键词 UI互动应用评分统计状态管理数据处理多目标评分 一、功能说明 评分统计工具允许用…

递归实现指数型枚举(递归)

92. 递归实现指数型枚举 - AcWing题库 每个数有选和不选两种情况 我们把每个数看成每层&#xff0c;可以画出一个递归搜索树 叶子节点就是我们的答案 很容易写出每dfs函数 dfs传入一个u表示层数 当层数大于我们n时&#xff0c;去判断每个数字的选择情况&#xff0c;输出被选…

Linux相关概念和易错知识点(25)(信号原理、操作系统的原理、volatile)

目录 1.信号的产生 &#xff08;1&#xff09;kill &#xff08;2&#xff09;raise、abort 2.对block、pending、handler表的管理 &#xff08;1&#xff09;信号集&#xff08;sigset_t&#xff09; &#xff08;2&#xff09;block表的管理 ①操作相关的函数 ②sigpr…

opencv中的色彩空间及其转换

在 OpenCV 中&#xff0c;色彩空间&#xff08;Color Space&#xff09;指的是表示颜色的一种方式&#xff0c;或是用数学模型对颜色的表达。不同的色彩空间采用不同的方式来描述颜色的三要素&#xff08;如亮度、饱和度、色调&#xff09;&#xff0c;因此可以在不同的应用场景…

大模型微调---Prompt-tuning微调

目录 一、前言二、Prompt-tuning实战2.1、下载模型到本地2.2、加载模型与数据集2.3、处理数据2.4、Prompt-tuning微调2.5、训练参数配置2.6、开始训练 三、模型评估四、完整训练代码 一、前言 Prompt-tuning通过修改输入文本的提示&#xff08;Prompt&#xff09;来引导模型生…

Edge Scdn用起来怎么样?

Edge Scdn&#xff1a;提升网站安全与性能的最佳选择 在当今互联网高速发展的时代&#xff0c;各种网络攻击层出不穷&#xff0c;特别是针对网站的DDoS攻击威胁&#xff0c;几乎每个行业都可能成为目标。为了确保网站的安全性与稳定性&#xff0c;越来越多的企业开始关注Edge …

通信技术以及5G和AI保障电网安全与网络安全

摘 要&#xff1a;电网安全是电力的基础&#xff0c;随着智能电网的快速发展&#xff0c;越来越多的ICT信息通信技术被应用到电力网络。本文分析了历史上一些重大电网安全与网络安全事故&#xff0c;介绍了电网安全与网络安全、通信技术与电网安全的关系以及相应的电网安全标准…

批量提取zotero的论文构建知识库做问答的大模型(可选)——含转存PDF-分割统计PDF等

文章目录 提取zotero的PDF上传到AI平台保留文件名代码分成20个PDF视频讲解 提取zotero的PDF 右键查看目录 发现目录为 C:\Users\89735\Zotero\storage 写代码: 扫描路径‘C:\Users\89735\Zotero\storage’下面的所有PDF文件,全部复制一份汇总到"C:\Users\89735\Downl…

精准采集整车信号:风丘混合动力汽车工况测试

一 背景 混合动力汽车是介于纯电动汽车与燃油汽车两者之间的一种新能源汽车。它既包含纯电动汽车无污染、启动快的优势&#xff0c;又拥有燃油车续航便捷、不受电池容量限制的特点。在当前环境下&#xff0c;混合动力汽车比纯电动汽车更符合目前的市场需求。 然而&#xff0c…

带标题和不带标题的内部表

什么是工作区&#xff1f; 什么是工作区&#xff1f;简单来说&#xff0c;工作区是单行数据。它们应具有与任何内部表相同的格式。它用于一次处理一行内部表中的数据。 内表和工作区的区别 &#xff1f; 一图胜千言 内表的类型 有两种类型的内表&#xff1a; 带 Header 行…

【图像分类实用脚本】数据可视化以及高数量类别截断

图像分类时&#xff0c;如果某个类别或者某些类别的数量远大于其他类别的话&#xff0c;模型在计算的时候&#xff0c;更倾向于拟合数量更多的类别&#xff1b;因此&#xff0c;观察类别数量以及对数据量多的类别进行截断是很有必要的。 1.准备数据 数据的格式为图像分类数据集…

React系列(八)——React进阶知识点拓展

前言 在之前的学习中&#xff0c;我们已经知道了React组件的定义和使用&#xff0c;路由配置&#xff0c;组件通信等其他方法的React知识点&#xff0c;那么本篇文章将针对React的一些进阶知识点以及React16.8之后的一些新特性进行讲解。希望对各位有所帮助。 一、setState &am…