MySQL 分区表设计

1、分区表设计方案

当设计 MySQL 分区表时,需要考虑以下几个方面:分区策略、分区字段、分区数量和分区函数。下面是一个详细的示例,展示了如何设计和执行分区表的增删改查操作。

设计分区表:

考虑一个订单表的例子,我们可以按照订单创建时间对表进行范围分区。

CREATE TABLE orders (order_id INT NOT NULL AUTO_INCREMENT,order_date DATE,customer_id INT,total_amount DECIMAL(10, 2),PRIMARY KEY (order_id, order_date)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='这是一个分区表,按月份分区'
PARTITION BY RANGE (YEAR(order_date)) (PARTITION p0 VALUES LESS THAN (2020),PARTITION p1 VALUES LESS THAN (2021),PARTITION p2 VALUES LESS THAN (2022),PARTITION p3 VALUES LESS THAN MAXVALUE
);

上述示例中,我们创建了一个名为 orders 的分区表,并按照 order_date 字段的年份进行范围分区,总共有四个分区。

插入数据到分区表:
INSERT INTO orders (order_date, customer_id, total_amount) VALUES('2021-01-01', 1001, 50.00),('2021-02-15', 1002, 100.00),('2022-03-10', 1003, 200.00);

上述示例向分区表插入了三条订单数据,分别属于不同的分区。

查询分区表数据:
SELECT * FROM orders WHERE order_date >= '2021-01-01' AND order_date < '2022-01-01';

上述示例查询了 orders 表中 2021 年的订单数据。

更新分区表数据:
UPDATE orders SET total_amount = 150.00 WHERE order_id = 1 AND order_date = '2021-01-01';

上述示例更新了 orders 表中指定订单的金额。

删除分区表数据:
DELETE FROM orders WHERE order_date >= '2022-01-01';

上述示例删除了 orders 表中 2022 年及之后的订单数据。

这些示例涵盖了分区表的设计和基本操作。但请注意,在实际使用分区表时,还需要根据具体需求和数据特征进行细致的设计和调整。同时,还应考虑性能优化、索引策略和维护操作等因素。

2、普通表转换分区表

将一个已经存在的普通表转换为分区表需要进行以下步骤:

创建分区表

创建一个与原表结构完全相同的分区表,但不包含分区定义。例如,假设我们要将现有的 my_table 表转换为分区表。

CREATE TABLE my_partitioned_table (-- 复制原表的所有列和约束...
) PARTITION BY ...; -- 分区定义留空

将原表的数据插入到分区表中。可以使用 INSERT INTO ... SELECT 语句将数据复制到分区表中。

INSERT INTO my_partitioned_table (...)
SELECT ... FROM my_table;

停止对原表的写入操作,并记录最后一次写入的时间点(例如通过添加一个新列来记录)。

重命名原表,并将分区表重命名为原表的名称。

ALTER TABLE my_table RENAME TO my_table_old;
ALTER TABLE my_partitioned_table RENAME TO my_table;

根据转换前的原表的写入时间点,更新分区表的分区定义。

ALTER TABLE my_table REORGANIZE PARTITION ...;

这里的 PARTITION ... 部分取决于您选择的分区策略和分区字段。通过 REORGANIZE PARTITION 语句,您可以重新定义分区范围,并将数据移动到相应的分区中。

完成后,您可以根据需要重新建立索引、重新生成统计信息等操作。请注意,在进行此过程时,确保先进行适当的备份,并在开发环境中进行充分的测试,以避免数据丢失或其他潜在问题。此外,由于转换过程可能会带来一些停机时间或性能影响,请在合理的维护窗口内进行转换。

3、datetime字段按月分区

要按照 datetime 类型字段按月进行分区,可以使用 MySQL 的范围分区策略和日期函数。下面是一个示例,演示如何按月对表进行分区:

创建分区表:
CREATE TABLE my_partitioned_table (id INT,event_date DATETIME
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='这是一个分区表,按月份分区'
PARTITION BY RANGE COLUMNS(event_date) (PARTITION p0 VALUES LESS THAN ('2023-01-01'),PARTITION p1 VALUES LESS THAN ('2023-02-01'),PARTITION p2 VALUES LESS THAN ('2023-03-01'),PARTITION p3 VALUES LESS THAN ('2023-04-01'),...PARTITION pn VALUES LESS THAN MAXVALUE
);

上述示例中,我们创建了一个名为 my_partitioned_table 的分区表,并根据 event_date 列的范围进行分区。每个分区对应一个月份,范围是从每月的第一天到下一个月的第一天。

插入数据到分区表:
INSERT INTO my_partitioned_table (id, event_date) VALUES(1, '2023-01-05'),(2, '2023-01-15'),(3, '2023-02-10'),(4, '2023-03-25');```
上述示例向分区表插入了四条数据,分别属于不同的月份。
查询特定月份的数据:
SELECT * FROM my_partitioned_table PARTITION (p1);

上述示例查询了 my_partitioned_table 表中 2023 年 2 月的数据。
通过按月分区,可以更加高效地查询特定时间范围内的数据。同时,请确保在插入或更新数据时,将数据插入到正确的分区中,以避免跨分区查询的性能问题。

4、datetime 只分月不分年实现

要实现只对分月而不分年的分区,可以使用MySQL的范围分区策略。下面是一个示例,演示如何按照月份对表进行分区:

创建分区表:
CREATE TABLE my_partitioned_table (id INT,event_date DATE
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='这是一个分区表,按月份分区'
PARTITION BY RANGE (MONTH(event_date)) (PARTITION p0 VALUES LESS THAN (2),PARTITION p1 VALUES LESS THAN (3),PARTITION p2 VALUES LESS THAN (4),PARTITION p3 VALUES LESS THAN (5),...PARTITION pn VALUES LESS THAN (13)
);

上述示例中,我们创建了一个名为 my_partitioned_table 的分区表,并根据 event_date 列的月份进行分区。每个分区对应一个月份,范围是从112

插入数据到分区表:
INSERT INTO my_partitioned_table (id, event_date) VALUES(1, '2023-01-05'),(2, '2023-01-15'),(3, '2023-02-10'),(4, '2023-03-25');```
上述示例向分区表插入了四条数据,分别属于不同的月份。#### 查询特定月份的数据:
```sql
SELECT * FROM my_partitioned_table PARTITION (p1);

上述示例查询了 my_partitioned_table 表中2月份的数据。

通过按照月份进行分区,可以更加高效地查询特定月份的数据。请注意,上述示例没有分区年份,如果需要包含多年的数据,可以将分区范围扩展到跨越多年的月份。同时,请确保在插入或更新数据时,将数据插入到正确的分区中,以避免跨分区查询的性能问题。

5、datetime 只分月不分年,查询范围数据

如果只对分月而不分年,并且想要查询两年内的数据,可以使用MySQL的范围-列表混合分区策略。以下是一个示例,演示如何实现该需求:

创建分区表:
CREATE TABLE my_partitioned_table (id INT,event_date DATE
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='这是一个分区表,按月份分区'
PARTITION BY RANGE (YEAR(event_date))
SUBPARTITION BY LIST (MONTH(event_date)) (PARTITION p0 VALUES LESS THAN (2022) (SUBPARTITION s0 VALUES IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)),PARTITION p1 VALUES LESS THAN (2024) (SUBPARTITION s1 VALUES IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12))
);

上述示例中,我们创建了一个名为 my_partitioned_table 的分区表,并根据 event_date 列的年份和月份进行分区。每个年份的分区再根据月份进行子分区。范围分区设置为2022年至2023年的数据。

插入数据到分区表:
INSERT INTO my_partitioned_table (id, event_date) VALUES(1, '2022-12-15'),(2, '2023-01-10'),(3, '2023-05-20'),(4, '2023-12-25');

上述示例向分区表插入了四条数据,跨越了两年的数据。

查询两年内的数据:
SELECT * FROM my_partitioned_table
WHERE event_date >= '2022-01-01' AND event_date < '2024-01-01';

上述示例查询了 my_partitioned_table 表中2022年至2023年的所有数据。
通过使用范围-列表混合分区策略,并根据实际需求设置分区边界和子分区边界,可以实现只对分月不分年,并查询两年内数据的功能。

6、truncate 分区表

MySQL中,可以使用 ALTER TABLE 语句来截断(empty)分区表的指定分区。以下是一个示例,演示如何对分区表进行分区截断:

ALTER TABLE my_partitioned_table TRUNCATE PARTITION partition_name;

在上述示例中,将 my_partitioned_table 替换为您的分区表的名称,将 partition_name 替换为要截断的分区的名称。
请注意,截断分区将删除该分区中的所有数据,并将分区清空。只有当分区表使用了范围分区或列表分区策略时才能进行分区截断操作。

如果想要截断多个分区,可以使用逗号分隔不同的分区名称,如下所示:

ALTER TABLE my_partitioned_table TRUNCATE PARTITION partition_name1, partition_name2;

上述示例将截断 partition_name1partition_name2 两个分区。

请谨慎执行分区截断操作,因为它会永久删除分区中的数据,并且无法恢复。在执行此操作之前,请确保已经备份了重要的数据。

7、创建分区表,id主键报错

报错信息:

A Primary key must include all columns in the tables partition function

在创建按月分区表时,如果使用了分区函数对表进行分区,主键必须包含表中的所有列,并且还需要包含用于分区的列。这是因为根据分区函数将数据分配到不同的分区时,需要确保每个分区中的数据都具有唯一性。

以下是一个示例,展示如何在创建按月分区表时设置主键,其中包含分区列和其他列:

CREATE TABLE my_partitioned_table (id INT,event_datetime DATETIME,-- 其他列PRIMARY KEY (event_datetime, id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='这是一个分区表,按月份分区'
PARTITION BY RANGE (MONTH(event_datetime)) (-- 分区定义PARTITION p0 VALUES LESS THAN (2),PARTITION p1 VALUES LESS THAN (3),PARTITION p2 VALUES LESS THAN (4),PARTITION p3 VALUES LESS THAN (5),PARTITION p4 VALUES LESS THAN (6),PARTITION p5 VALUES LESS THAN (7),PARTITION p6 VALUES LESS THAN (8),PARTITION p7 VALUES LESS THAN (9),PARTITION p8 VALUES LESS THAN (10),PARTITION p9 VALUES LESS THAN (11),PARTITION p10 VALUES LESS THAN (12),PARTITION p11 VALUES LESS THAN (13)
);

在上述示例中,我们通过在 CREATE TABLE 语句中指定 PRIMARY KEY 来设置主键。主键包括了分区列 event_datetime 和其他列 id。这样可以确保每个分区中的数据具有唯一性。
请根据您的表结构和需求,调整主键的具体定义。

8、各分区 count 合计

要计算所有分区表中的数据条目总数,可以使用以下示例代码:

SELECT SUM(PARTITION_ROWS) -- TABLE_ROWS
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME = 'your_partitioned_table';AND PARTITION_NAME IS NULL;

在上述示例中,请将 'your_partitioned_table' 替换为您实际的分区表名称。执行此查询后,将返回分区表中所有分区的数据条目总数。

请注意,这里使用了 INFORMATION_SCHEMA.PARTITIONS 系统表来获取分区表的相关信息。PARTITION_ROWS 是该表中存储的每个分区的数据行数。通过对所有分区的行数求和,可以得到整个分区表的数据条目总数。

当执行上述查询时,确保拥有足够的权限来访问 INFORMATION_SCHEMA.PARTITIONS 表,并且已正确指定分区表的名称。

9、分区剪枝 (Partition Pruning

分区剪枝(Partition Pruning)是 MySQL 的优化器在执行查询时自动进行的一种技术,用于排除不相关的分区,以减少扫描的数据量。以下是一个示例来说明分区剪枝的工作原理:

假设有一个按时间分区的表 sales,其中包含 iddateamount 字段。表按每年一个分区进行分区,命名为 p2020p2021p2022、等等。现在我们想查询某个时间范围内的销售额。

SELECT SUM(amount)
FROM sales
WHERE date BETWEEN '2021-01-01' AND '2022-12-31';

在执行上述查询时,MySQL 的优化器会自动应用分区剪枝技术,只选择与查询条件相关的分区进行扫描。在这个示例中,优化器会识别出只有 p2021p2022 这两个分区包含所需的数据,其他分区则可以被排除在外。

通过分区剪枝,优化器会生成一个优化的执行计划,只对涉及的分区进行扫描,从而减少了查询的数据量和处理的开销,提高了查询的性能。

需要注意的是,在使用分区剪枝时,查询条件必须与分区键相关才能生效。如果查询条件不与分区键相关,优化器将无法剪枝分区,会扫描所有的分区。

此外,分区剪枝还可以与其他查询优化技术(如索引使用、统计信息等)结合使用,以提高查询性能。

总之,分区剪枝是 MySQL 的一种自动优化技术,通过排除不相关的分区来减少查询的数据量,从而提高查询性能。它在处理大型分区表和时间范围查询时特别有用。

10、分区表预留空间(默认)

Navicat 中创建分区表时,可能会出现 "50100" 的情况,这是由于 Navicat 预留了一部分空间用于存储分区信息。

MySQL 中,对于每个分区表,都需要一个默认分区(也称为无效分区),以便处理不属于任何其他分区的数据。这个默认分区需要占用一定的空间,即 50100 字节。因此,在 Navicat 中创建分区表时,会为默认分区预留这部分空间。

当你在 Navicat 中创建分区表时,可以忽略这个默认分区,因为它只是用来处理无法匹配到其他分区的数据。如果你没有自定义默认分区的话,MySQL 会自动将这些数据放入默认分区中。

请注意,这个 "50100" 的大小是 MySQL 的默认值,如果你在 MySQL 配置中更改了默认值,那么在 Navicat 中创建分区表时,预留的空间大小可能会有所不同。

总结来说,Navicat 在创建分区表时会预留一部分空间用于默认分区,这是正常的行为,不需要过多关注。

11、mysql 复制表
非同库实现方案

在目标数据库中创建一个与源表结构相同的新表:

CREATE TABLE 目标库名.新表名 LIKE 源库名.原表名;

这将在目标数据库中创建一个名为 “新表名” 的新表,其结构与源数据库中的 “原表名” 相同。

将源表的数据插入到目标表中:

INSERT INTO 目标库名.新表名 SELECT * FROM 源库名.原表名;

这将从源表中选择所有数据,并将其插入到目标表中。

同库复制表
CREATE TABLE 新表名 LIKE 原表名;
INSERT INTO 新表名 SELECT * FROM 原表名;
12、mysql 8.0 以下 truncate 分区表锁表

MySQL 5.7.30(系统版本)及更早版本中,使用 TRUNCATE TABLE 命令对分区表进行操作时会锁定整个表,这可能导致其他会话在执行期间被阻塞。

  • 1.使用 DELETE 命令替代 TRUNCATE:如果 TRUNCATE TABLE 操作会导致表锁定问题,可以考虑改用 DELETE FROM命令来删除表中的所有行。DELETE命令是逐行删除的,因此不会锁定整个表。请注意,DELETE命令在删除大量数据时可能效率较低,因为它会记录日志和生成回滚段。

  • 2.分段 TRUNCATE:将大的分区表拆分成多个较小的分区,然后分别执行 TRUNCATE TABLE 命令。这样可以减少锁定的粒度,并降低对整个表的锁定时间。但是,这种方法需要重构分区表结构,可能会造成一些额外的工作。

  • 3.升级到MySQL 8.0或更高版本:MySQL 8.0引入了一项重要的改进,即针对TRUNCATE TABLE命令的分区锁定进行了优化。在MySQL 8.0及更高版本中,TRUNCATE PARTITION 语法可用于仅清空特定分区而不锁定整个表。因此,升级到MySQL 8.0或更高版本可能是一个解决方案。

不升级mysql、truncate方案

如果你不能升级MySQL版本,但仍然希望在线执行 TRUNCATE PARTITION 操作并避免锁表,可以考虑以下方法:

使用分区交换:将要清空的分区与一个空分区进行交换。这样可以实现快速清空分区的效果,而不会锁定整个表。具体步骤如下:

  • 1.创建一个空的临时分区,可以是已存在的空分区或者新创建的分区。
    使用 ALTER TABLE 进行分区交换操作,将要清空的分区与空分区进行交换,例如:
ALTER TABLE your_table EXCHANGE PARTITION p_to_truncate WITH TABLE empty_partition;

这个操作是原子的,并且不会锁定整个表。
最后,删除交换后的空分区。
通过使用分区交换,你可以在不锁定整个表的情况下快速清空指定的分区。

  • 2.使用临时表(离线):将要清空的分区数据复制到一个临时表中,并通过 RENAME 操作进行切换。具体步骤如下:

创建一个临时表,结构与原分区表相同。
使用 INSERT INTO ... SELECT 将要清空的分区数据复制到临时表中。
使用 RENAME TABLE 进行表名切换,将原分区表重命名为备份表,将临时表重命名为原分区表的名称。
最后,删除备份表。
这种方法需要一定的额外存储空间来保存临时表和备份表,但可以实现在线清空分区而不锁定整个表。

MySQL 分区表设计相关推荐

  1. sql 拆分_实践参考:MySQL架构设计从开发规范、选型、拆分到减压实战指南

    导引 作者,李辉,原新浪爱彩票运维负责人,常用网名:门牙没了.曾主导新浪爱彩票的MySQL运维工作.培训合伙人.资深讲师,中国科学院大学在读研究生(大数据方向),擅长大型项目的关系型数据库运维和管理, ...

  2. mysql表分区数量限制_详解MySQL分区表的局限和限制的代码实例

    本文对Mysql分区表的局限性做了一些总结,因为个人能力以及测试环境的 原因,有可能有错误的地方,还请大家看到能及时指出,当然有兴趣的朋友可以去官方网站查阅. 禁止构建 分区表达式不支持以下几种构建: ...

  3. 什么是MySQL分区表

    简介 分区是指根据一定的规则,数据库把一个表分解成多个更小的.更容易管理的部分. 就访问数据库的应用而言,逻辑上只有一个表或一个索引,但是实际上这个表可能由数 10 个物理分区对象组成,每个分区都是一 ...

  4. Vertica 分区表设计(续)

    在上篇Vertica 分区表设计中,已经提过了Vertica的分区表创建和分区删除,但举例上并不系统, 本篇文章将系统的对分区表设计及后续的删除分区进行讲解. 概述:Vertica分区表(天和月)创建 ...

  5. mysql 分区表 归档_MySQL分区表

    1,MySQL分区表作用 当单表的数据量较大,需要进行定期的数据归档删除时,或者提高查询性能,都可以采用分区: 2,分区表设置 分区的种类 range分区 list分区 hash分区 key分区 ra ...

  6. 不属于mysql常量的是_MySQL中,下面______常量的写法是不正确的?-智慧树MySQL数据库设计与应用章节答案...

    MySQL数据库设计与应用:MySQL中,下面______常量的写法是不正确的?[?ж???] A:'2.1E5 B:0x123abc C:b'121' D:null MySQL数据库设计与应用章节测 ...

  7. 面试mysql中怎么创建索引_阿里面试:MySQL如何设计索引更高效?

    有情怀,有干货,微信搜索[三太子敖丙]关注这个不一样的程序员. 本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试完整考点.资料以及我的系列文章. ...

  8. 数据切分——Mysql分区表的管理与维护

    关于Mysql分区表的介绍可以参考: http://blog.csdn.net/jhq0113/article/details/44592865 关于Mysql分区表的创建可以参考: http://b ...

  9. mysql数据库设计的原则_MySQL数据库设计原则

    转自 http://www.supidea.com/post/mysql_design_database.aspx MySQL数据库设计原则 MySQL对于成为一个非常快速的数据库服务器有着当之无愧的 ...

  10. MYSQL数据库设计原则

    一.MYSQL数据库设计原则 1.核心原则 不在数据库做运算; cpu计算务必移至业务层; 控制列数量(字段少而精,字段数建议在20以内); 平衡范式与冗余(效率优先:往往牺牲范式) 拒绝3B(拒绝大 ...

最新文章

  1. [Unity UGUI]点击和长按组件
  2. 【转载】如何学JavaScript?前辈的经验之谈
  3. Linux VNC黑屏(转)
  4. Python基础教程(008)--第一个Python程序
  5. AGC005D - ~K Perm Counting(组合数学,背包,dp)
  6. Android 短信解析
  7. CentOS7 /etc/profile 添加环境变量重开终端后不生效
  8. 三星电子预计第三季度营业利润达722亿元 同比增长58%
  9. windowfullscreen后键盘布局顶上去_手机输入法的派别之争,九宫格和全键盘究竟哪种更科学?...
  10. PHP5 Session 使用详解(一)
  11. 启动orcal服务和监听的命令的一种方式
  12. 前后落差大用什么词语_形容前后反差大的词语
  13. 一个熟练程序员所具备的特质-2
  14. 免费邮箱客户端设置方法大全
  15. 小米Mix2s刷机教程
  16. 前缀学习完结篇 第三课上
  17. android开发百度地图步行导航
  18. file.exists()方法,明明存在,
  19. ViewFlipper和ViewPager的区别
  20. 积分不等式证明的三种方法_20160416

热门文章

  1. Java常用查询表格(持续整理,更新。。。)
  2. 我的移动开发春季历程,已整理成文档
  3. alipay支付宝招聘
  4. Gradle的版本差异导致无法编译:Could not initialize class com.android.build.gradle.internal.TaskManager
  5. js编写代码实现多人聊天室
  6. 卫星导航算法 --geo 库函数的学习
  7. 【机器学习】处理不平衡的数据集
  8. php网站手机端title,HTML5移动端手机网站基本模板
  9. 全固态发射机——雷达基础知识
  10. 职场高效的秘诀,竟是一个“懒”字