【问题标题】:mysql partitioning does not workmysql分区不起作用
【发布时间】:2017-02-27 15:28:52
【问题描述】:

我有一个表,字段是 action_time 主键,类型是日期时间

我尝试在分区上打破它

ALTER TABLE foo PARTITION BY RANGE (MONTH(action_time))
(
PARTITION p01 VALUES LESS THAN (02) ,
PARTITION p02 VALUES LESS THAN (03) ,
PARTITION p03 VALUES LESS THAN (04) ,
PARTITION p04 VALUES LESS THAN (05) ,
PARTITION p05 VALUES LESS THAN (06) ,
PARTITION p06 VALUES LESS THAN (07) ,
PARTITION p07 VALUES LESS THAN (08) ,
PARTITION p08 VALUES LESS THAN (09) ,
PARTITION p09 VALUES LESS THAN (10) ,
PARTITION p10 VALUES LESS THAN (11) ,
PARTITION p11 VALUES LESS THAN (12) ,
PARTITION p12 VALUES LESS THAN (13) ,
PARTITION pmaxval VALUES LESS THAN MAXVALUE 
);

在 phpmyadmin 中,我看到带有行的分区 但是当我执行

explain partitions select * from foo where action_time between '2017-01-01 20:34:08' and '2017-01-21 20:34:08';

或

explain partitions select * from foo where action_time > '2017-01-01 20:34:08' && action_time < '2017-01-21 20:34:08'

它命中所有分区 (p01,p02,p03,p04,p05,p06,p07,p08,p09,p10,p11,p12,pmaxval)

我做错了什么?

我也尝试这种方式同样的结果

ALTER TABLE foo
  PARTITION BY RANGE(  YEAR(action_time) )
  SUBPARTITION BY HASH( MONTH(action_time) )
  SUBPARTITIONS 12 (
    PARTITION p2015 VALUES LESS THAN (2016),
    PARTITION p2016 VALUES LESS THAN (2017),
    PARTITION p2017 VALUES LESS THAN (2018),
    PARTITION p2018 VALUES LESS THAN (2019),
    PARTITION p2019 VALUES LESS THAN (2020),
    PARTITION p2020 VALUES LESS THAN (2021),
    PARTITION p2021 VALUES LESS THAN (2022),
    PARTITION p2022 VALUES LESS THAN (2023),
    PARTITION p2023 VALUES LESS THAN (2024),
    PARTITION p2024 VALUES LESS THAN (2025),
    PARTITION p2025 VALUES LESS THAN (2026),
    PARTITION p2026 VALUES LESS THAN (2027),
    PARTITION p2027 VALUES LESS THAN (2028),
    PARTITION p2028 VALUES LESS THAN (2029),
    PARTITION p2029 VALUES LESS THAN (2030),
    PARTITION pmax VALUES LESS THAN MAXVALUE
  );

我需要按年和月分解表以改善选择时间,当我在不应该在整个表中搜索的日期之间进行选择时,它应该在相关分区中搜索。我该怎么做?

【问题讨论】:

    标签: mysql partitioning


    【解决方案1】:

    您找到了PARTITIONing 几乎无用的另一个原因。

    假设您指定了BETWEEN '2015-11-05' AND '2017-02-02'。它需要击中哪些分区?全部。

    假设您指定了BETWEEN '2015-11-05' AND '2016-02-02'。它需要击中哪些分区? 4,但它不够聪明,无法环绕。所以它会(我认为)击中一切。

    只有有限数量的模式(MONTH() 不是其中之一)分区将“正确”。

    要使BY RANGE( some date ) 工作,您只能使用BY RANGE(TO_DAYS(date))(以及其他一些)。但是你必须每个月(或者经常)创建一个新分区。并且,可选地,DROP 最旧的分区。

    现在你计划的另一个原因可能没用。您期望从分区中获得什么好处?也许是性能?可能不会给您带来任何性能优势。让我们看看您的查询,以便我解释原因。

    一个简单的

    SELECT ...
        WHERE date >= '...'
          AND date  < '...' + INTERVAL 20 DAY
    

    使用INDEX(date) 与使用分区时一样快。可能更快。

    如果WHERE 中还有其他内容,那么一切都会改变。

    My PARTITION blog

    为什么 PARTITIONing 不能加速简单查询

    假设您有一个简单的SELECT,它有一个非常好的索引,例如您指定PRIMARY KEY 的确切值。 (这称为“点查询”。)

    案例 1:非分区表。索引使用 BTree 结构。在一百万行中定位特定记录需要深入 BTree,这将是大约 3 级深。对于 10 亿行,它可能是 5 个级别。

    案例 2:分区表。分区将表拆分为多个表,每个表都有索引。定位特定行首先必须定位特定分区(子表),然后向下钻取该分区的较浅 BTree。

    认为它是否(可能)从 BTree 中删除了一层,但增加了到达分区的额外努力。性能差异是微乎其微的。你是赢了还是输了还不清楚。 (缓存、数据结构等使这种分析变得复杂。)

    结论:对于点查询,分区永远不会有帮助,假设您在非分区等效项上有一个合适的索引。

    您的特定查询是一个简单的“范围”查询:WHERE action_time BETWEEN ... AND ...

    最优的表结构(包括分区和索引)是

    • 没有分区
    • INDEX(action_time)

    另一个注意事项:如果涉及多个分区,SELECT 会从每个分区(修剪后)获取行(如果有),将它们放在一起,然后可能必须对结果进行排序(取决于SELECT 中的其他条款)。可惜查询的执行没有并行性,因此分区变体涉及更多,因此可能更慢。

    【讨论】:

    • 还有一些规则,比如 type='...' 和 m_id='...' 这个表很大,里面有很多日常记录,我认为分区加速选择跨度>
    • 而且,通过您的新编辑,您找到了一个示例,说明为什么我说SUBPARTITION 没用。
    • 我在回答中添加了“为什么 PARTITIONing 不能加快简单查询”。
    【解决方案2】:
    分区修剪不支持

    MONTH()。目前MySQL 5.7/8.0只支持四个函数。

    在 MySQL 8.0 中,TO_DAYS() 支持分区修剪, TO_SECONDS()、YEAR() 和 UNIX_TIMESTAMP() 函数。见第 5 章, 分区修剪,了解更多信息。

    您必须改用 TO_DAYS()。例如

    ALTER TABLE foo PARTITION BY RANGE (TO_DAYS(action_time))
    (
      PARTITION p01 VALUES LESS THAN (TO_DAYS('2017-02-01')) ,
      PARTITION p02 VALUES LESS THAN (TO_DAYS('2017-03-01')) ,
      PARTITION pmaxval VALUES LESS THAN MAXVALUE 
    );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-12-13
      • 1970-01-01
      • 1970-01-01
      • 2013-06-20
      • 2021-10-28
      • 2016-02-12
      • 2015-05-30
      相关资源
      最近更新 更多