mysql 分区错误 主键必须包含表分区函数中的所有列



在MySQL 8上,我有这个表:

CREATE TABLE `float_values` (
`id` bigint UNSIGNED NOT NULL,
`attribute_id` bigint UNSIGNED NOT NULL,
`value` double(8,2) NOT NULL,
`created_at` date NOT NULL,
`updated_at` date NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
ALTER TABLE `float_values`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `float_values_created_at_unique` (`created_at`);
ALTER TABLE `float_values`
MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT;
COMMIT;

使用此架构:

Schema::create('float_values', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('attribute_id');
$table->float('value');
$table->date('created_at');
$table->date('updated_at');
});

创建表后,我这样做是为了对created_at列进行分区:

ALTER TABLE float_values 
PARTITION BY HASH( YEAR(created_at) )
PARTITIONS 4

但我收到此错误:

静态分析:

在分析过程中发现了 1 个错误。

无法识别的更改操作。(靠近位置 0 的 "(SQL查询:

通过哈希( 年份(created_at( 更改表float_values分区 分区 4

MySQL 说: 文档

1503 - 主键必须包含表分区函数中的所有列

我知道这个问题是重复的,但答案对我没有帮助!

错误说我们必须宣布created_at为主键,但我们不能有两个主键,我created_at更改为唯一,但问题仍然存在

https://dev.mysql.com/doc/refman/8.0/en/partitioning-limitations-partitioning-keys-unique-keys.html 说:

分区表的分区表达式中使用的所有列都必须是该表可能具有的每个唯一键的一部分。

换句话说,表上的每个唯一键都必须使用表的分区表达式中的每一列。这还包括表的主键,因为根据定义,它是唯一键。

对于许多想要在 MySQL 中使用表分区的人来说,这是一个障碍。不能始终按要作为分区依据的列进行分区,因为它要么不在唯一键中,要么表中存在其他唯一(或主(键。

请记住:分区表达式必须是表的每个唯一键的一部分。

即使created_at是唯一键,此表的主键仍然位于id列上。

如果您同时具有主键和唯一键,则无法在MySQL表上使用分区,并且这两个键没有共同的列。

我找到了答案。

当我迁移表时,它在 id 上创建了一个主增量列,因此当我执行 alter 分区查询时,它告诉我分区列必须是主键! 我要做的是在我的架构中创建一个没有主键和增量列的表,然后在一个没有任何主键的简单表之后,我确实创建了一个包含id 的主键,created_at如下列:

首先是这个:

CREATE TABLE `float_values` (
`id` bigint UNSIGNED NOT NULL,
`attribute_id` bigint UNSIGNED NOT NULL,
`value` double(8,2) NOT NULL,
`created_at` date NOT NULL,
`updated_at` date NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

使用此架构:

Schema::create('float_values', function (Blueprint $table) {
$table->unsignedBigInteger('id');
$table->unsignedBigInteger('attribute_id');
$table->float('value');
$table->date('created_at');
$table->primary(['id', 'created_at']);
$table->date('updated_at');
});

然后是这个查询:

alter TABLE float_values add primary key (`id`, `created_at`)

PARTITION BY HASH是无用的;不要费心弄清楚如何让它工作。

此外,作为一般规则,除非至少有一百万行,否则分区没有用。 既然你要求UNIQUEDATE,我怀疑你的行数不会超过几千行。

如果您想解释表的用途、最终大小、使用 Hash 的目标以及您将使用的一些SELECTs,我可能会解释如何在不分区的情况下实现您的目标。

场景:

对于这些查询:

... WHERE id = 111 AND created_at BETWEEN ... AND ... -- case 1
... WHERE attribute_id = 222                             -- case 2
... WHERE attribute_id = 333 AND created_at BETWEEN ... AND ... -- case 3

然后,您的表可能是未分区的:

CREATE TABLE `float_values` (
`id` bigint UNSIGNED NOT NULL  AUTO_INCREMENT,  -- debatable
`attribute_id` bigint UNSIGNED NOT NULL,
`value` double(8,2) NOT NULL,
`created_at` date NOT NULL,
`updated_at` date NOT NULL
PRIMARY KEY(id),                   -- for case 1
INDEX(attribute_id, created_at)    -- for cases 2, 3
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

最新更新