每天几千万行是相当多的。
假设:
- 每天只有 1000 万条新记录;
- 您的表格仅包含您在问题中提到的列;
url
是TEXT
平均(Punycode)长度约为77 个字符的类型;
pageviews
是类型INT
;
int_views
是类型INT
;
ext_views
是类型INT
;和
datetime
是类型DATETIME
那么每天的数据将占用大约 9.9 × 10 8个字节,几乎是 1GiB/天。实际上它可能要多得多,因为上述假设相当保守。
除其他事项外, MySQL 的最大表大小由其数据文件所在的底层文件系统确定。如果您在 Windows 或 Linux 上使用 MyISAM 引擎(如您在下面的评论中所建议的那样)而不进行分区,那么几个 GiB 的限制并不少见;这意味着该表将在一个工作周内达到其容量!
正如@Gordon Linoff提到的,您应该对表进行分区;但是,每个表有 1024 个分区的限制。每天 1 个分区(这在您的情况下是非常明智的),在分区开始被重用之前,您将被限制在一个表中存储 3 年以下的数据。
因此,我建议您将每年的数据保存在自己的表中,每个表都按天分区。此外,正如@Ben 解释的那样,复合索引(datetime, url)
会有所帮助(我实际上建议创建一个date
列DATE(datetime)
并为其编制索引,因为它将使 MySQL在执行查询时能够修剪分区);并且,如果行级锁定和事务完整性对您不重要(对于此类表,它们可能不重要),使用 MyISAM 可能并不愚蠢:
CREATE TABLE news_2012 (
INDEX (date, url(100))
)
Engine = MyISAM
PARTITION BY HASH(TO_DAYS(date)) PARTITIONS 366
SELECT *, DATE(datetime) AS date FROM news WHERE YEAR(datetime) = 2012;
CREATE TRIGGER news_2012_insert BEFORE INSERT ON news_2012 FOR EACH ROW
SET NEW.date = DATE(NEW.datetime);
CREATE TRIGGER news_2012_update BEFORE UPDATE ON news_2012 FOR EACH ROW
SET NEW.date = DATE(NEW.datetime);
如果您选择使用MyISAM ,您不仅可以存档已完成的年份myisampack
(MERGE
使用,但它只对语句有用,因为视图既不可更新也不可插入):UNION
VIEW
SELECT
UNION
DROP TABLE news;
CREATE TABLE news (
date DATE,
INDEX (date, url(100))
)
Engine = MERGE
INSERT_METHOD = FIRST
UNION = (news_2012, news_2011, ...)
SELECT * FROM news_2012 WHERE FALSE;
然后,您可以在此合并表上运行上述查询(以及任何其他查询):
SELECT url, SUM(pageviews), SUM(int_views), SUM(ext_views)
FROM news
WHERE date = '2012-08-29'
GROUP BY url
ORDER BY SUM(pageviews) DESC
LIMIT 10;