數千行每天是相當多的。
假設:
- 每天只有10萬個新的記錄;
- 您的表格僅包含您在問題中提及的列;
url
是TEXT
類型的具有〜77 characters平均(Punycode碼)長度;
pageviews
是INT
類型;
int_views
是INT
類型;
ext_views
類型INT
;和
datetime
是類型DATETIME
的然後每一天的數據會佔據周圍9.9 字節,這是幾乎1GiB /天。實際上它可能更多,因爲上述假設非常保守。
MySQL的maximum table size是確定的,除其他事項外,通過在其上的數據文件所在的底層文件系統。如果您在Windows或Linux上不使用分區的情況下使用MyISAM引擎(如您的評論所建議的那樣),那麼幾個GiB的限制並不少見;這意味着桌子在一個工作周內就能達到它的容量!
正如@Gordon Linoff提到的,你應該partition你的表;但是,每個表都有1024個分區的limit。有了1個分區/天(在您的情況下這將是非常明智的),您將被限制在分區開始重用之前將3年以下的數據存儲在單個表中。
因此,我建議你保持每一年的數據在它自己的表,每一天劃分。此外,作爲@Ben explained,在(datetime, url)
上的複合索引將有所幫助(我實際上建議創建一個的date
列並對其進行索引,因爲它將在執行查詢時啓用MySQL到prune分區);並且,如果行級鎖和事務的完整性是對你並不重要(對於這種表,它們可能不是),使用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
一個包括所有潛在的一年表(一個替代方案,也將在InnoDB中工作的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;
什麼是表上的索引和什麼解釋查詢的計劃? – Ben
@Ben,索引在url和datetime上。什麼是解釋計劃? – egidra
@Ben,我如何做一個明確的字符到日期轉換?日期時間列的數據類型是日期時間。 MySQL爲我們做了從字符到日期時間類型的轉換嗎?我認爲它的確如此。應該從0:00到23:59選擇24小時的數據。 – egidra