在mysql中分区或分离一个非常大的表

时间:2014-03-01 17:07:24

标签: mysql sql

我们在mysql中有一个非常大的表,其中包含500,000,000条记录,每秒有100个请求(SELECT)。
这是架构:

id(int), 
user_id (int), 
content(text), 
date(datetime)

由于高达90%的请求是在过去6个月内。我的问题是提高绩效。 将这些记录从过去6个月中的另一个表中分离出来并将SELECT从中分离出来是一个好主意,还是使用分区方法快速获取过去6个月的所有记录。

或者,如果有更好的方法......

例如,查询是这样的。

SELECT content,user_id FROM log
JOIN users ON users.id = log.user_id
WHERE date > DATE_SUB(CURDATE(), INTERVAL 180 DAY)
LIMIT 15

user_id,日期在表Log中编入索引 表Users中有200万用户。

1 个答案:

答案 0 :(得分:3)

您的编辑说您以每小时三分之一的速度使用此类查询。

 SELECT content,user_id 
   FROM log
   JOIN users ON users.id = log.user_id
  WHERE date > DATE_SUB(CURDATE(), INTERVAL 180 DAY)
  LIMIT 15

我将冒昧地重写此查询以完全限定您的列选择。

 SELECT log.content,
        log.user_id 
   FROM log                                  /* one half gigarow table */
   JOIN users ON users.id = log.user_id      /* two megarow table */
  WHERE log.date > DATE_SUB(CURDATE(), INTERVAL 180 DAY)
  LIMIT 15

(如果不正确,请考虑更新您的问题。)

为什么要加入此查询中的users表?你的结果似乎都不是来自它。为什么这个查询不能满足您的需求?

 SELECT log.content,
        log.user_id 
   FROM log                                  /* one half gigarow table */
  WHERE log.date > DATE_SUB(CURDATE(), INTERVAL 180 DAY)
  LIMIT 15

如果您想更快地进行此查询,请在(date,user_id, content)上添加覆盖索引的复合词。该覆盖索引将支持范围扫描和快速检索。如果您的content列实际上是TEXT(LOB)类型,则需要将(date,user_id)放入覆盖索引中,并且检索速度会慢一些。

您是否使用JOIN确保返回的日志条目在users?中具有匹配条目?如果是,请更好地解释您的查询。

您绝对可以根据日期范围对表格进行分区。但是你需要改变你的桌子,或者重新创建并重新填充它,这将导致停机或巨大的争夺。

http://dev.mysql.com/doc/refman/5.6/en/partitioning-range.html

像这样的DDL应该为你做的伎俩

CREATE TABLE LOG (
  id         INT NOT NULL AUTO_INCREMENT,  /*maybe BIGINT? */
  user_id    INT NOT NULL,
  `date`     DATETIME NOT NULL,
  content    TEXT,
  UNIQUE KEY (id, `date`),
  KEY covering (`date`,user_id)
) 
PARTITION BY RANGE COLUMNS(`date`) (
    PARTITION p0 VALUES LESS THAN ('2012-01-01'),
    PARTITION p1 VALUES LESS THAN ('2012-07-01'),
    PARTITION p2 VALUES LESS THAN ('2013-01-01'),
    PARTITION p3 VALUES LESS THAN ('2013-07-01'),
    PARTITION p4 VALUES LESS THAN ('2014-01-01'),
    PARTITION p5 VALUES LESS THAN ('2014-07-01'),
    PARTITION p6 VALUES LESS THAN ('2015-01-01'),
    PARTITION p7 VALUES LESS THAN ('2015-07-01')
);

请注意,UNIQUE KEY有一些关于猴子的事情。进入分区功能的列也需要出现在所谓的主键中。

稍后,当2015年7月(分区p7的截止日期)接近时,您可以运行此语句为下一个六个月的时间段添加分区。

   ALTER TABLE `log` 
 ADD PARTITION (PARTITION p8 VALUES LESS THAN ('2016-01-01'))

但是,严重的是,如果您的查询有不必要的连接或索引覆盖率差,这个分区垃圾都不会有太大帮助。它将使您的数据库管理更加复杂。