在mysql中划分或分离非常大的表

在mysql中划分或分离非常大的表,mysql,sql,Mysql,Sql,mysql中有一个非常大的表,其中有500000000条记录,每秒有100个请求(SELECT)。 这是一个模式: id(int), user_id (int), content(text), date(datetime) 用户id、日期在表Log 表users中有200万用户。您的编辑说,您以每小时三分之一的速度使用这样的查询 SELECT content,user_id FROM log JOIN users ON users.id = log.user_id WH

mysql中有一个非常大的表,其中有500000000条记录,每秒有100个请求(
SELECT
)。
这是一个模式:

id(int), user_id (int), content(text), date(datetime) 用户id、日期在表
Log


users

中有200万用户。您的编辑说,您以每小时三分之一的速度使用这样的查询

 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
如果要加快此查询,请在
(日期、用户id、内容)
上放置一个复合覆盖索引。此覆盖索引将支持范围扫描和快速检索。如果您的
内容
列实际上是文本(LOB)类型,则只需将
(日期、用户id)
放入覆盖索引,您的检索速度会稍微慢一些

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

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

像这样的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')
);
请注意,关于
唯一键
,有一些胡闹。进入分区函数的列也需要出现在所谓的主键中

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

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

但是,说真的,如果您的查询有不必要的连接或较差的索引覆盖率,那么这些分区垃圾都不会有多大帮助。这将使您的数据库管理更加复杂。

如果要拆分表,您将如何处理其他10%的数据?特别是,当日期范围同时包含两个时间段时,一个表无法覆盖它。合并存储引擎如何?您是否有日期索引?是的,我有日期索引,但读取时间仍然太长。10秒进行简单的选择。@Alexander我想我可以为每次插入写两个表。并在辅助表上创建一个事件,自动删除日期>6个月的记录,您认为如何?好吧,我加入
用户
表,从
用户
表中获取每行用户id的信息。事实上,我不确定
SELECT&JOIN
是否更快,或者
SELECT user\u id,content FROM log
来填充一个用户id列表,然后再执行另一个
SELECT information FROM users
来获取这些
用户
信息。您可以在应用程序中这样做吗?取决于用户数量,但我的大多数应用程序都有一个按ID定期更新的用户缓存,因为它们是静态的(当ID不在缓存中时,缓存会命中数据库)。没有必要把这些东西推到数据库上——但这完全取决于你拥有的用户类型(facebook不同于小型公司的会计系统)。我使用大量的静态查找数据(其中一些有一百万行长)来实现这一点。那么,您没有展示您运行的实际查询的示例吗?如果你有几十排,那没关系。限制15的目的是什么?你到底想完成什么?因为你在千兆行范围内,所有这些都很重要。不,我写了我的查询,我有超过5亿行。我在这篇文章的最后一条评论中提到,我不知道两者的区别。你的意思是我永远不应该参加这样一张大桌子的聚会?没有“永远”这样的事。如果要联接这两个表,则这两个表上的索引都很重要。存储引擎(InnoDB?)和其他细节也是如此。为什么在180天前的午夜之后,您选择了15行日志的任意块?你说得越多,这里的人就越能帮助你。
   ALTER TABLE `log` 
 ADD PARTITION (PARTITION p8 VALUES LESS THAN ('2016-01-01'))