PARTITION Maintenance in MySQL by Rick James
取自 Rick’s RoTs - Rules of Thumb for MySQL (需要)
AUTO_INCREMENT 字段可以作为混合主键的第一部分,或者non-UNIQUE索引的一部分
使用分区解决性能问题是如此的诱人,但是很多情况下实事并非如此.
PARTITIONing 拆分一个表中的数据到若干个小的分区表中.但是引起性能问题的原因不是表的大小通常,而是I/O时间和索引.
一个经常的错误认识:“分区将使得许多查询更快”.我不这么认为.仔细想一下,精确的查找需要消耗什么?
没有分区,但是有合适的索引的情况下,BTree索引可以直接命被中查找的数据行.对一百万行数据来说,可能只需要5层深度的BTree.
使用分区,第一步分区选择命中然后打开,然后一个小的BTree(4层树深)直接命中.好吧,更浅的树的代价是需要打开分区.
类似的,如果你查看需要访问的缓存磁盘块,你会意识到两种情况几乎访问了相同数据量的磁盘快.
总所周知磁盘稍描是一个查询的主要消耗,因此分区不能获取任何性能改善(至少在这个中情况下).
下面的二维情况,会得出来的一个矛盾的结论.
或许分区在数据库中最通常有效的适用场景就是需要周期性的从表中删除‘旧’的数据.
按天分区(或者其他uint格式的时间)可以让你用瞬间删除或者添加分区来替代慢的多的DELETE,这片blog主要讨论这种情况.
这种适用场景也在Big DELETEs讨论过
对于这个场景DROP PARTITION比DELETEing 大量数据块的多的多
索引一半来说都是一维的,如果你在你的where条件中需要两个范围,请尝试将其中一个迁移到PARTITIONing中
查找地图最近的10个匹萨店就需要一个2维的索引,排序修建过的分区可以作为第二个维度.参见Latitude/Longitude Indexing
上面的例子使用了PARTITION BY RANGE(latitude)和 PRIMARY KEY(longitude, …)
对于这个场景将大大减少稍描的行数
这个场景解释起来有点复杂,设想下下面几种情况
对于这个场景通过提升缓存适用效率来减少I/O,提升操作性能
使用EXPORT/IMPORT partition 归档或者导入数据.(导入可能需要一些 partition key 的技巧).
参见Transportable Tablespaces for InnoDB Partitions
这个连接针对5.7版本,但是有一个章节“5.6版本怎么做?”
参考(See also FLUSH TABLES … FOR EXPORT), 直到5.6.17版本,分区InnoDB表仍然是不支持的
对于这个场景可以快速的移动分区在不同的服务器和数据库之间
注意到现在为止,各种场景中我们只使用了RANGE partitioning,其他的并没有被使用.
让我们把注意力放在管理情景#1的情况
假设你有一张大的数据表,在一张表上添加新数据,并定期的归档整理到其他表中,例如新闻,日志,以及其他的有时效性消息.分区是一种极好的解决方案
根据数据类型和多久数据过期,你可以按天,按周或者按小时等分区
没有简单的sql语句,来‘删除最近30天的分区’ 或者 ‘添加一个明天的分区’,手工做这件事情将是非常麻烦的.
ALTER TABLE tbl
DROP PARTITION from20120314;
ALTER TABLE tbl
REORGANIZE PARTITION future INTO
from20120415 VALUES LESS THAN (TO_DAYS('2012-04-16')),
future VALUES LESS THAN MAXVALUE;
After which you have...
CREATE TABLE tbl (
dt DATETIME NOT NULL, -- or DATE
...
PRIMARY KEY (..., dt),
UNIQUE KEY (..., dt),
...
)
PARTITION BY RANGE (TO_DAYS(dt)) (
start VALUES LESS THAN (0),
from20120315 VALUES LESS THAN (TO_DAYS('2012-03-16')),
from20120316 VALUES LESS THAN (TO_DAYS('2012-03-17')),
...
from20120414 VALUES LESS THAN (TO_DAYS('2012-04-15')),
from20120415 VALUES LESS THAN (TO_DAYS('2012-04-16')),
future VALUES LESS THAN MAXVALUE
);
或许你已经注意到例子中一些趣的东西,下面解释下.
范围中多了一天(03/16-04/16): 最后一天是部分完整的.
为什么使用一个伪造的”start”分区?如果使用了一个非法的日期(3月31号),那么在转换成datetime的时候结果将是null,而null值是被放到第一个分区上的因为所有的select可能都包含了不可用的日期(关于这一点可以展开来说明),导致分区选择的结果中始终包含第一个分区,然后查找第一个个分区,因此如果select肯定会稍描第一个分区,那么保持第一个分区为空将会更为的高效.
更多的讨论参见The Data Charmer
5.5版本中使用新的语法避免了使用伪造分区 PARTITION BY RANGE COLUMNS(dt) (PARTITION day_20100226 VALUES LESS THAN (‘2010-02-27’), …
下一个关于”future”分区,早晚有一天用来添加新分区的cron/EVENT可能执行过程中发生了错误,最坏的结果就是丢失了一天的数据.预防丢失数据的最简的方法就是有个分区来捕捉这样的数据,虽然通常情况下这个分区是空的.
有一个”future”分区是的添加分的脚本变得复杂了些,它需要处理讲明天的数据移从”future”动到新分区中.这是用到了REORAGNIZE命令.通常情况下,是没有数据要移动的,所以基本上不会花费时间.
就像我反复提到的,在许多方面,BY RANGE可能是仅有的用法,并且时间序列数据对分区来说是最常用的.
Months, Quarters, etc: Concoct a notation that works.
使用多少个分区?
Reference implementation, in Perl, with demo of daily partitions
代码中最复杂的部分在发现PARTITION名称,尤其是最老的和下一个分区.
执行这个例子需要
execute perl demo_part_maint.pl to get the rest of the instructions
这段代码将生成并执行(需要的时候)下面两个中的一个
ALTER TABLE tbl REORGANIZE PARTITION
future
INTO (
PARTITION from20150606 VALUES LESS THAN (736121),
ARTITION future VALUES LESS THAN MAXVALUE
)
ALTER TABLE tbl DROP PARTITION from20150603
PARTITIONing requires at least MySQL 5.1
The tips in this document apply to MySQL, MariaDB, and Percona.
More on PARTITIONing
LinkedIn discussion
Future (as envisioned in 2016):
MySQL 8.0, released Sep, 2016:
Native partitioning will give:
Contact me by posting a question at MySQL Forums :: Partitions
- - Rick James