按范围列分区意外行为

Partitioning by range columns unexpected behavior

我有 MySQL table 按范围列分区(c_id 和 created_at) 我创建了 2 个分区:

  1. logs_1_2020(c_id 小于 2 且创建时间小于 2021-01-01 00:00:00)

  2. logs_1_2021(c_id 小于 2 且创建时间小于 2022-01-01 00:00:00)

当我运行

INSERT INTO example_log_table (c_id, data, created)
    VALUES (1, 'test', '2021-10-24 18:16:08')

我应该找到存储在 logs_1_2021 中的结果,但当我在 logs_1_2020 中找到她时,我感到震惊。

有人对此有解释吗?

此 table SQL 生成器:

CREATE TABLE example_log_table (
                        id int auto_increment ,
                        c_id int,
                        data TEXT NOT NULL,
                        created DATETIME NOT NULL,
                        primary key (id,c_id,created)
) PARTITION BY RANGE columns (c_id,created)(
    PARTITION logs_1_2020 VALUES LESS THAN  (2,'2021-01-01 00:00:00'),
    PARTITION logs_1_2021 VALUES LESS THAN  (2,'2022-01-01 00:00:00')
);

当您使用多列作为分区键时,放置基于元组比较。您可以通过这种方式测试一个元组是否小于另一个元组 (MySQL 8.0):

select row(1, '2021-10-24 18:16:08') < row(2, '2021-01-01 00:00:00');
+---------------------------------------------------------------+
| row(1, '2021-10-24 18:16:08') < row(2, '2021-01-01 00:00:00') |
+---------------------------------------------------------------+
|                                                             1 |
+---------------------------------------------------------------+

元组不等式比较的规则很棘手。我建议你仔细阅读https://dev.mysql.com/doc/refman/8.0/en/partitioning-columns-range.html and https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_less-than

For row comparisons, (a, b) < (x, y) is equivalent to:

(a < x) OR ((a = x) AND (b < y))

在这种情况下,1小于2,因此您插入的元组小于定义分区上限的元组logs_1_2020

您还可以考虑如果要使用 ORDER BY c_id,created 查询一组行,数据将如何排序。它会首先按 c_id 排序,然后只有在 c_id 上有平局的情况下,它才会按 created.

对平局排序

除非你有充分的理由进行分区,否则将其删除并将索引更改为

PRIMARY KEY(c_id, created, id),
INDEX(id)

如果您希望拥有大量数据并希望删除“旧数据”,则 PARTITION BY RANGE 超过 created;这有助于周期性 DROP PARTITION。并且上面的两个索引仍然有效和有用。

经过大量搜索有没有办法让Mysql根据列值而不是元组比较将数据插入分区 我决定像这样制作我的分区:

        PARTITION logs_1_2020 VALUES LESS THAN  (1,'2021-01-01'),
        PARTITION logs_2_2020 VALUES LESS THAN  (2,'2021-01-01'),
        PARTITION logs_2_2021 VALUES LESS THAN  (2,'2022-01-01')

并且在插入时,我插入了第一个参数,以使 Mysql 比较第二个参数是否更少。

所以当 运行 :

INSERT INTO example_log_table (c_id, created) VALUES (2, '2021-10-21')

将在 logs_2_2021 处插入,因为 c_id 匹配并且创建的小于第二行创建的