2015-11-02 83 views
1

我有一个表,我想使用MySQL 5.7分区,以减轻我与快速下探旧数据有问题分区。 (另外,它会是不错的增加我插入/通过划分跨比迄今为止其他东西O性能,尤其是如果我计划子分区跨越多个卷分片)MySQL的分区中,日期和INT

下面是表的简化版本:

CREATE TABLE `tbl` (
    `date` date NOT NULL, 
    `sub_id` int(11) unsigned NOT NULL, 
    `cmd_id` int(11) NOT NULL, 
    `code` TINYINT DEFAULT NULL, 
    `rqst` VARCHAR(32) NOT NULL DEFAULT '', 
    UNIQUE KEY `uk1` (sub_id,cmd_id,date) 
) ENGINE=InnoDB 

(note that use of column 'date' in uk1 is only to allow partitioning on date) 
(The true unique key is (sub_id,cmd_id)) 

这里是SQL语句我做该表:

1. INSERT INTO tbl (NOW(), ...) 
2. UPDATE tbl SET code=$code WHERE sub_id=$sub_id AND cmd_id=$cmd_id 
3. SELECT code,rqst FROM tbl WHERE sub_id=$sub_id AND cmd_id=$cmd_id 

这里是分区方案,到目前为止我已经设计:

PARTITION BY RANGE (TO_DAYS(date)) 
SUBPARTITION BY HASH(sub_id) 
SUBPARTITIONS 4 
(PARTITION d001 VALUES LESS THAN (736250) ENGINE = InnoDB, 
PARTITION d002 VALUES LESS THAN (736260) ENGINE = InnoDB, 
PARTITION d003 VALUES LESS THAN (736270) ENGINE = InnoDB, 
PARTITION d004 VALUES LESS THAN (736280) ENGINE = InnoDB, 
PARTITION d005 VALUES LESS THAN (736290) ENGINE = InnoDB, 
PARTITION d006 VALUES LESS THAN (736300) ENGINE = InnoDB, 
PARTITION d007 VALUES LESS THAN (736310) ENGINE = InnoDB, 
PARTITION d008 VALUES LESS THAN (736320) ENGINE = InnoDB, 
PARTITION d009 VALUES LESS THAN (736330) ENGINE = InnoDB, 
PARTITION d010 VALUES LESS THAN (736340) ENGINE = InnoDB, 
PARTITION d011 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) 

不过,我相信,这将通过每次我参考时间(sub_id,cmd_id)要求每每个分区的读取损害性能:

EXPLAIN PARTITIONS SELECT * FROM tbl WHERE sub_id='107' AND cmd_id='2246806'; 
+----+-------------+-------+------------------------------------------------------------------------------------------------------------------------------------------------+------+---------------+------+---------+-------------+------+-------------+ 
| id | select_type | table | partitions                                  | type | possible_keys | key | key_len | ref   | rows | Extra  | 
+----+-------------+-------+------------------------------------------------------------------------------------------------------------------------------------------------+------+---------------+------+---------+-------------+------+-------------+ 
| 1 | SIMPLE  | optz | d001_d001sp1,d002_d002sp1,d003_d003sp1,d004_d004sp1,d005_d005sp1,d006_d006sp1,d007_d007sp1,d008_d008sp1,d009_d009sp1,d010_d010sp1,d011_d011sp1 | ref | uk1   | uk1 | 38  | const,const | 11 | Using where | 
+----+-------------+-------+------------------------------------------------------------------------------------------------------------------------------------------------+------+---------------+------+---------+-------------+------+-------------+ 

所以我的问题的症结是:

  • 如果我通过d日期当时它的d-1额外查找分区
  • 如果我用S sub_id的分区,然后我不能轻易砸日期
  • 分区,我不看我怎么可以用柱体P artitioning

这里有一些注意事项/警告:

  • 插入约5-20million行/天
  • 读平等分配,写,插入 - 但总是单列
  • 只需要保留过去〜个月的数据
  • 复制系统已到位
  • 涉及的硬件很贵
  • 我不希望在唯一密钥中包含date列,但之后我无法对其进行分区,因此代码确保(sub_id,cmd_id)在各个日期之间都是唯一的。

谢谢!

+0

您的评论显示为“数据月份”,但分区似乎约为10 * 10天。 –

回答

1

BY HASH基本上是无用的,因为是SUBPARTITIONs

缓解我快速删除旧数据时遇到的问题。

也就是说,你需要DROP PARTITIONdate?使用PARTITION BY RANGE (TO_DAYS(date)),不要打扰子分区。

为了清楚起见,改变UNIQUE KEY uk1 (sub_id,cmd_id,date)PRIMARY KEY (sub_id,cmd_id,date)

[编辑姗姗来迟]你的三个查询将与这样的工作还算不错。SELECTUPDATE将不得不命中所有分区,因为date不在WHERE子句中。 INSERT将仅命中最新的分区(因为NOW())。

更多讨论,包括做好定期清除提示:数据

http://mysql.rjweb.org/doc.php/partitionmaint

只需要保持过去的一个月〜推荐约32分区 - 一个悬而未决DROP,一个future;看链接。

复制系统是到位

做好ALTER TABLE添加分区将停止系统,但我想你明白的问题在那里。

我不想以包括唯一密钥的日期列,但后来我不能上它分区,所以代码确保(sub_id,cmd_id)是唯一横跨日期,因为它主张。

是的,一个必要的邪恶。

5-20million行/天

这是每秒几百一个最大?如果您有摄入速度问题,请参阅http://mysql.rjweb.org/doc.php/staging_table

+0

一个折中的办法是保持大约38天 - 每周6个分区。这将减少'SELECT'和'UPDATE'的数量分区,但增加所需的磁盘空间,同时仍提供“DROP PARTITION”的效率。 –

+0

谢谢,这很有帮助,在我做这篇原创文章之前,我实际上花了一些时间通过您的网站阅读;)在我有机会阅读更多内容之后,我会更新此评论并提供有关您的答案的问题。再次感谢。 – gfunk