您的编辑表明您以每小时百万分之一的速度使用此类查询。
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'))
但是,说真的,如果您的查询有不必要的连接或索引覆盖率低,那么这些分区垃圾都不会有太大帮助。这将使您的数据库管理更加复杂。