MYSQL的分区字段,必须包含在主键字段内

本文探讨了MYSQL在创建分区表时,分区字段必须包含在主键字段内的原因及解决方法,通过两种策略成功实现分区,并强调了主键与分区字段间的关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MYSQL的分区字段,必须包含在主键字段内
 
MYSQL的分区字段,必须包含在主键字段内
在对表进行分区时,如果分区字段没有包含在主键字段内,如表A的主键为ID,分区字段为createtime ,按时间范围分区,代码如下:
CREATE TABLE T1 (
     id int(8) NOT NULL AUTO_INCREMENT,
     createtime datetime NOT NULL,
      PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
PARTITION BY RANGE(TO_DAYS (createtime))
(
PARTITION p0 VALUES LESS THAN (TO_DAYS('2010-04-15')),
PARTITION p1 VALUES LESS THAN (TO_DAYS('2010-05-01')),
PARTITION p2 VALUES LESS THAN (TO_DAYS('2010-05-15')),
PARTITION p3 VALUES LESS THAN (TO_DAYS('2010-05-31')),
PARTITION p4 VALUES LESS THAN (TO_DAYS('2010-06-15')),
PARTITION p19 VALUES LESS ThAN  MAXVALUE);
错误提示:#1503
 A PRIMARY KEY MUST INCLUDE ALL COLUMNS IN THE TABLE'S PARTITIONING FUNCTION
MySQL主键的限制,每一个分区表中的公式中的列,必须在主键/unique key 中包括
 
在MYSQL的官方文档里是这么说明的
18.5.1. Partitioning Keys, Primary Keys, and Unique Keys
This section discusses the relationship of partitioning keys with primary keys and unique keys. The rule governing this relationship can be expressed as follows: All columns used in the partitioning expression for a partitioned table must be part of every unique key that the table may have. 
 
In other words,every unique key on the table must use every columnin the table's partitioning expression. (This also includes the table's primary key, since it is by definition a unique key. This particular case is discussed later in this section.) For example, each of the following table creation statements is invalid: 
分区字段必须包含在主键字段内,至于为什么MYSQL会这样考虑,优快云的斑竹是这么解释的:
为了确保主键的效率。否则同一主键区的东西一个在A分区,一个在B分区,显然会比较麻烦。
 
下面讨论解决办法,毕竟在一张表里,日期做主键的还是不常见。 
方法1: 
顺应MYSQL的要求,就把分区字段加入到主键中,组成复合主键
CREATE TABLE T1 (
     id int(8) NOT NULL AUTO_INCREMENT,
     createtime datetime NOT NULL,
      PRIMARY KEY (id,createtime)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
PARTITION BY RANGE(TO_DAYS (createtime))
(
PARTITION p0 VALUES LESS THAN (TO_DAYS('2010-04-15')),
PARTITION p1 VALUES LESS THAN (TO_DAYS('2010-05-01')),
PARTITION p2 VALUES LESS THAN (TO_DAYS('2010-05-15')),
PARTITION p3 VALUES LESS THAN (TO_DAYS('2010-05-31')),
PARTITION p4 VALUES LESS THAN (TO_DAYS('2010-06-15')),
PARTITION p19 VALUES LESS ThAN  MAXVALUE);
 测试通过,分区成功。
 
方法2: 
既然MYSQL要把分区字段包含在主键内才能创建分区,那么在创建表的时候,先不指定主键字段,是否可以呢?? 
测试如下:
CREATE TABLE T1 (
     id int(8) NOT NULL ,
     createtime datetime NOT NULL
      ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
PARTITION BY RANGE(TO_DAYS (createtime))
(
PARTITION p0 VALUES LESS THAN (TO_DAYS('2010-04-15')),
PARTITION p1 VALUES LESS THAN (TO_DAYS('2010-05-01')),
PARTITION p2 VALUES LESS THAN (TO_DAYS('2010-05-15')),
PARTITION p3 VALUES LESS THAN (TO_DAYS('2010-05-31')),
PARTITION p4 VALUES LESS THAN (TO_DAYS('2010-06-15')),
PARTITION p19 VALUES LESS ThAN  MAXVALUE);
测试通过,分区成功。OK
继续添加上主键
alter table t1 add PRIMARY KEY(ID)
错误1503,和前面一样的错误。
alter table t1 add PRIMARY KEY(ID,createtime)
创建主键成功,但还是复合主键,看来是没办法了,必须听指挥了。
主键创建成功,把ID加上自增字段设置
alter table t1 change id id int not null auto_increment;
alter table t1 auto_increment=1;
 
最后结论,MYSQL的分区字段,必须包含在主键字段内。 
 
### MySQL 分区字段的创建、管理和优化 #### 创建分区字段MySQL中,为了实现高效的查询性能和数据管理效率,在创建表时需考虑将特定字段设置分区字段。值得注意的是,如果要对一张表实施分区操作,则该表定义中的主键必须包含所选作分区依据的那个字段[^1]。 对于希望延迟指定主键的情况,理论上可以在最初建表时不设定任何主键,之后再通过修改表结构的方式来增加主键并确保其包含了作为分区标准的列。然而这种做法并不推荐,因为这可能会引发一系列复杂性和潜在的风险,比如影响现有应用程序逻辑或者造成索引失效等问题。 ```sql CREATE TABLE example ( id INT NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id, created_at), -- 主键包含分区字段created_at INDEX idx_created_at(created_at) ) PARTITION BY RANGE (TO_DAYS(created_at))( PARTITION p0 VALUES LESS THAN (TO_DAYS('2023-01-01')), PARTITION p1 VALUES LESS THAN (TO_DAYS('2024-01-01')) ); ``` 上述SQL语句展示了如何创建一个带有日期范围分区的例子,并且注意到了`PRIMARY KEY`声明里加入了用来做分区的关键字`created_at`。 #### 管理分区字段 一旦建立了分区表,后续可能还需要对其进行维护工作,如添加新的分区、删除旧有的分区或是重新组织现有的分区布局等。这些任务可以通过执行相应的DDL(Data Definition Language)命令来完成: - **添加新分区** 当业务增长导致原有预设的最大值不足以覆盖当前需求时,就需要扩展分区边界了。此时可采用`ALTER TABLE ... ADD PARTITION`语法向已有范围内追加额外区间。 ```sql ALTER TABLE example ADD PARTITION ( PARTITION p2 VALUES LESS THAN (TO_DAYS('2025-01-01')) ); ``` - **移除过期分区** 随着时间推移某些早期的数据或许已经不再具有价值而被允许清理掉,这时就可以借助于`DROP PARTITION`子句安全地释放这部分资源而不至于破坏整个架构稳定性。 ```sql ALTER TABLE example DROP PARTITION p0; ``` - **重组现存分区** 有时出于性能考量或者其他原因想要调整已存在的分区分割方式,那么可以运用`REORGANIZE PARTITION`来进行灵活变动。 ```sql ALTER TABLE example REORGANIZE PARTITION p1 INTO ( PARTITION p_new_1 VALUES LESS THAN (TO_DAYS('2023-07-01')), PARTITION p_new_2 VALUES LESS THAN MAXVALUE ); ``` 以上三种情况分别对应着不同场景下的常规操作模式[^2]。 #### 优化分区字段 针对大规模数据集而言,合理规划好分区策略能够极大地改善读写速度及降低I/O消耗。具体措施如下所示: - 使用适合的应用场景:例如按照时间戳进行划分非常适合日志记录类应用;按地理位置分布则适用于地理信息系统(GIS)[^3]。 - 控制单个分区大小:保持各部分之间相对均衡有助于平衡负载压力,防止个别热点区域形成瓶颈效应。 - 定期评估与重构:随着环境变化和技术进步不断审视既有设计是否仍然最优解,必要时候果断采取行动予以改进。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值