需要帮助在位列上对 MySQL table 进行分区,并对结果分区进行子分区

Need help partitioning a MySQL table on a bit column with subpartitioning on resulting partitions

我需要一些帮助来弄清楚如何在 MySQL 数据库中对下面的 table 进行分区,以便我首先有 2 个分区,1 个活跃用户(active column = true) 和另一个非活跃用户。然后我想按年对非活动用户分区进行子分区(在 archive_key 列上,数据类型为 YEAR(4))。我想我知道如何实现这一点,但我不敢尝试以防万一我没有正确执行它。

谁能帮我实现这个?我目前正在使用 MySQL 5.7 和 8 版本。感谢您提供的任何建议。

CREATE TABLE users_table (
  row_id int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  first_name varchar(255) DEFAULT NULL,
  last_name varchar(255) DEFAULT NULL,
  ...
  createdby varchar(255) DEFAULT NULL,
  createdat datetime DEFAULT NULL,
  lastmodby varchar(255) DEFAULT NULL,
  lastmodat datetime DEFAULT NULL,
  active bit(1) NOT NULL DEFAULT b'0',
  archive_key year(4) GENERATED ALWAYS AS (YEAR(createdat)) STORED,
  PRIMARY KEY (row_id, active),
)
ENGINE = INNODB,
AUTO_INCREMENT = 84771,
AVG_ROW_LENGTH = 166,
CHARACTER SET utf8,
COLLATE utf8_unicode_ci;

顺便说一句,喜欢分区给你带来的灵活性! MySQL 真的很棒!

子分区

MySQL 对子分区时可以做什么和不能做什么有很大限制,引用自 5.7 manual:

it is possible to subpartition tables that are partitioned by RANGE or LIST. Subpartitions may use either HASH or KEY partitioning

这意味着您正在查看这样的内容:

CREATE TABLE users_table (
  row_id int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  first_name varchar(255) DEFAULT NULL,
  last_name varchar(255) DEFAULT NULL,
  createdby varchar(255) DEFAULT NULL,
  createdat datetime DEFAULT NULL,
  lastmodby varchar(255) DEFAULT NULL,
  lastmodat datetime DEFAULT NULL,
  active bit(1) NOT NULL DEFAULT b'0',
  archive_key year(4),
  PRIMARY KEY (row_id, active, archive_key)
)
       ENGINE = INNODB,
       CHARACTER SET utf8,
       COLLATE utf8_unicode_ci
       PARTITION BY LIST(active)
           SUBPARTITION BY HASH(`archive_key`)
           SUBPARTITIONS 4
       (
            PARTITION inactive VALUES IN (0),
            PARTITION active   VALUES IN (1)
       );

注意PK中需要包含archive_key以避免

ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function

分区意见

不,它不摇滚。该论坛上介绍的大多数用例使用分区 运行 并不比不使用分区更快。在某些情况下,它们 运行 更慢。

当然,有很多选择。我看到实际性能改进的唯一一个是 PARTITION BY RANGE,但即便如此,也仅适用于狭窄的用例(清除时间序列,'find nearest',工作集位于 'bad' 的单个分区中索引,传输table table空格)。 Details

'partition pruning' 加速查询是一个神话。具有 suitable 索引的非分区 table 可能 运行 至少同样快。

注意:要利用添加(或删除)分区的优势,您必须重新评估索引。

在您的示例中,使用

进行非分区
INDEX(active, createdat)   -- in this order

WHERE active = 1
  AND createdat >= '2017/01/01'
  AND createdat  < '2017/01/01' + INTERVAL 1 YEAR

INDEX(active, active_key)   -- in this order

WHERE active = 1
  AND archive_key = '2017'

(前者不需要生成列)