【发布时间】:2013-10-21 17:03:50
【问题描述】:
我有一个巨大的表,其中存储了许多跟踪的事件,例如用户点击。
这张桌子已经有几十万,而且每天都在变大。 当我尝试从大的时间范围内获取事件时,查询开始变慢,并且在阅读了相当多的主题后,我了解到对表进行分区可能会提高性能。
我想做的是按月对表进行分区。
我只找到了显示如何每月手动分区的指南,有没有办法告诉 MySQL 按月分区,它会自动执行?
如果不是,考虑到我的按列分区是日期时间,手动执行的命令是什么?
【问题讨论】:
我有一个巨大的表,其中存储了许多跟踪的事件,例如用户点击。
这张桌子已经有几十万,而且每天都在变大。 当我尝试从大的时间范围内获取事件时,查询开始变慢,并且在阅读了相当多的主题后,我了解到对表进行分区可能会提高性能。
我想做的是按月对表进行分区。
我只找到了显示如何每月手动分区的指南,有没有办法告诉 MySQL 按月分区,它会自动执行?
如果不是,考虑到我的按列分区是日期时间,手动执行的命令是什么?
【问题讨论】:
如手册所述:http://dev.mysql.com/doc/refman/5.6/en/partitioning-overview.html
这很容易通过月份输出的哈希分区来实现。
CREATE TABLE ti (id INT, amount DECIMAL(7,2), tr_date DATE)
ENGINE=INNODB
PARTITION BY HASH( MONTH(tr_date) )
PARTITIONS 6;
请注意,这只是按月分区而不是按年分区,在这个例子中也只有 6 个分区(所以 6 个月)。
对于现有表的分区(手动:https://dev.mysql.com/doc/refman/5.7/en/alter-table-partition-operations.html):
ALTER TABLE ti
PARTITION BY HASH( MONTH(tr_date) )
PARTITIONS 6;
查询可以从整个表中完成:
SELECT * from ti;
或来自特定分区:
SELECT * from ti PARTITION (HASH(MONTH(some_date)));
【讨论】:
YEAR(tr_date) * 12 + MONTH(tr_date)
PARTITION BY HASH((YEAR(TIMESTAMP) * 100) + MONTH(TIMESTAMP)),它提供了格式良好的日期(201511、201512、201601 等)——尽管与 concat 函数相同
使用访问时间与表大小无关的 TokuDb。
【讨论】:
HASHing by month with 6 partitions 意味着一年有两个月将落在同一个分区中。这有什么好处?
不要打扰分区,索引表。
假设您只使用以下两个查询:
SELECT * from ti;
SELECT * from ti PARTITION (HASH(MONTH(some_date)));
然后以the_date 开头PRIMARY KEY。
第一个查询只是读取整个表;分区和不分区之间没有变化。
第二个查询,假设您想要一个月份,而不是映射到同一分区的所有月份,则需要
SELECT * FROM ti WHERE the_date >= '2019-03-01'
AND the_date < '2019-03-01' + INTERVAL 1 MONTH;
如果您还有其他疑问,我们来看看。
(我没有找到任何使用 PARTITION BY HASH 的性能理由。)
【讨论】:
CREATE TABLE `mytable` (
`post_id` int DEFAULT NULL,
`viewid` int DEFAULT NULL,
`user_id` int DEFAULT NULL,
`post_Date` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
PARTITION BY RANGE (extract(year_month from `post_Date`))
(PARTITION P0 VALUES LESS THAN (202012) ENGINE = InnoDB,
PARTITION P1 VALUES LESS THAN (202104) ENGINE = InnoDB,
PARTITION P2 VALUES LESS THAN (202108) ENGINE = InnoDB,
PARTITION P3 VALUES LESS THAN (202112) ENGINE = InnoDB,
PARTITION P4 VALUES LESS THAN MAXVALUE ENGINE = InnoDB)
【讨论】:
extract(year_month...)? (PARTITION 语句中可以有效使用的表达式数量非常有限。)
注意通过哈希进行分区的“懒惰”效应:
正如文档所说:
您还应该记住,每次插入或更新(或可能删除)行时都会计算此表达式;这意味着非常复杂的表达式可能会导致性能问题,尤其是在执行一次影响大量行的操作(例如批量插入)时。
最有效的散列函数是对单个表列进行操作并且其值随列值一致增加或减少的散列函数,因为这允许对分区范围进行“修剪”。也就是说,表达式与它所基于的列的值变化越紧密,MySQL 可以更有效地使用该表达式进行哈希分区。
例如,如果 date_col 是 DATE 类型的列,则表达式 TO_DAYS(date_col) 直接随 date_col 的值而变化,因为对于 date_col 的值的每一次变化,表达方式变化一致。表达式YEAR(date_col) 相对于date_col 的方差并不像TO_DAYS(date_col) 那样直接,因为并非date_col 中的所有可能变化都会在YEAR(date_col) 中产生等效变化。
【讨论】: