

当数据库的存储的数据超过一定的限度时,我们可以采用分区表的方式来进行优化,以解决数据库的性能问题。在《什么是MySQL分区?》一文中我们已经介绍了MySQL的分区。
这篇文章我们重点讨论一个使用分区时的注意事项:“分区键的值必须是有效的,因为MySQL不能将NULL值分配到分区。如果字段是NULL,数据库会报错。”
当看到这条注意事项时,想到一个场景,那就是如果分区键使用的是数据库默认生成的值,是否遵守这一规则呢?下面我们来看具体的场景。
在数据库表结构设计时,通常会包含两个通用字段created_at和updated_at,它们用来表示记录的创建时间和更新时间。
为了简化业务代码的处理,这两个字段在初始化时通常会采用数据库来生成默认时间戳,比如使用DEFAULT CURRENT_TIMESTAMP 或者 ON UPDATE CURRENT_TIMESTAMP 来自动生成值。这样业务代码便无需关注这两个字段,充分利用数据库的这个机制即可。
那么,如果恰好以created_at字段来定义时间字段分区,业务代码在执行INSERT操作时,没有对该字段赋值,即该字段为NULL。在这种情况下,是否会影响MySQL对分区的判断和处理?也就是说,是否符合最开始提到的注意事项?
答案是:即使应用程序的 SQL 中没有显式对 created_at 字段赋值,分区仍然是生效的。
MySQL的分区功能是基于分区键来工作的。当定义了分区之后,分区键的值由数据库在插入或更新记录时决定,无论这个值是应用程序显式赋值的,还是由MySQL自动生成的,只要该字段有值并符合分区规则,数据库的分区功能就会生效。
如果created_at字段的值采用默认值生成(比如 DEFAULT CURRENT_TIMESTAMP),MySQL 在插入数据时会自动根据当前时间填充该字段值,然后分区机制会根据该值在对应的分区中存储数据。
因此,即使应用程序在插入数据时没有指定 created_at 的值,分区仍然可以正常工作。
假设定义了分区表如下:
CREATE TABLE example_partitioned (
idINTNOTNULL,
created_at TIMESTAMPDEFAULTCURRENT_TIMESTAMP,
PRIMARY KEY (id, created_at)
) PARTITIONBYRANGE (YEAR(created_at)) (
PARTITION p2024 VALUESLESSTHAN (2024),
PARTITION p2025 VALUESLESSTHAN (2025),
PARTITION pmax VALUESLESSTHAN MAXVALUE
);
在此定义中,分区是基于 YEAR(created_at) 来划分的。注意,在创建分区时,表的主键(PRIMARY KEY)中要包含分区所使用的字段。
在上述表结构中,当数据记录插入时,若 created_at 字段未显式赋值,MySQL会自动生成当前时间戳。然后,MySQL会根据生成的时间戳计算分区键值(即 YEAR(created_at)),并将记录插入到相应的分区。
插入数据的例子:
INSERT INTO example_partitioned (id) VALUES (1);
执行时,created_at被MySQL默认赋值为当前时间(如 2025-12-03 23:10:10)。分区机制基于 YEAR(created_at) 计算分区,最终数据会存储到 p2025 分区中。
除了上述所说的“分区键的值必须是有效的,因为MySQL不能将NULL值分配到分区。如果字段是NULL,数据库会报错。”这一条注意事项外,在使用分区时,还需注意:
YEAR(created_at) = 2025,以便查询性能可以利用分区机制。MAXVALUE分区来确保能接收所有超出范围的值。因此,分区在这种情况下是可以正常工作的,即使应用层没有手动赋值created_at,MySQL的默认生成机制会确保分区生效。
全文完,感谢阅读,如果喜欢请三连。