mysql分区不起作用

时间:2017-02-27 15:28:52

标签: mysql partitioning

我有一个带字段的表,它是action_time主键,类型是datetime

我试图在分区上打破它

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
  );

我需要逐年打破表格以改善选择时间,当我在日期之间进行选择时,它不会在整个表格中搜索它应该在相关分区中搜索。我怎么能这样做?

2 个答案:

答案 0 :(得分: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级深度。对于十亿行,它可能是5个级别。

案例2:分区表。分区将表拆分为多个表,每个表都有索引。找到特定的行首先必须找到特定的分区(子表),然后深入查看该分区的较浅的BTree。

认为它是否(可能)从BTree中删除一个级别,但增加了为分区扩展的额外工作量。性能差异微不足道。目前尚不清楚你的成败。 (缓存,数据结构等使这种分析变得复杂。)

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

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

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

  • 没有分区
  • INDEX(action_time)

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

答案 1 :(得分:0)

分区修剪不支持

MONTH()。当前,MySQL 5.7/8.0仅支持四个功能。

  

在MySQL 8.0中,TO_DAYS()支持分区修剪,   TO_SECONDS(),YEAR()和UNIX_TIMESTAMP()函数。见第五章   分区修剪,以获取更多信息。

您必须使用 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 
);