1 日あたり数千万行というのは、かなりの数です。
仮定:
- 1 日あたりわずか 1,000 万件の新しいレコード。
- テーブルには、質問で言及した列のみが含まれています。
url
TEXT
平均 (Punycode) 長さが ~ 77 文字のタイプです。
pageviews
タイプINT
です。
int_views
タイプINT
です。
ext_views
タイプINT
です。と
datetime
タイプですDATETIME
その場合、毎日のデータは約 9.9 × 10 8バイトを占めることになり、これはほぼ 1GiB/日になります。上記の仮定は非常に保守的であるため、実際にはこれよりもかなり多くなる可能性があります。
MySQL の最大テーブル サイズは、とりわけ、そのデータ ファイルが存在する基礎となるファイル システムによって決まります。Windows または Linux でパーティショニングを行わずに MyISAM エンジン (以下のコメントで示唆されているように) を使用している場合、数 GiB の制限は珍しくありません。これは、テーブルが 1 週間以内に十分に容量に達することを意味します。
@Gordon Linoff が述べたように、テーブルを分割する必要があります。ただし、各テーブルには1024 個のパーティションの制限があります。1 日あたり 1 パーティション (これはあなたのケースでは差し迫って賢明なことです) では、パーティションが再利用され始める前に、1 つのテーブルに 3 年未満のデータを保存することに制限されます。
したがって、毎年のデータを独自のテーブルに保持し、それぞれを日ごとに分割することをお勧めします。さらに、@Ben が説明したように、複合インデックスが役立ちます (クエリの実行時に MySQL がパーティションをプルーニングできるようになるため、実際に列を作成してインデックスを(datetime, url)
作成することを提案します)。また、行レベルのロックとトランザクションの整合性が重要でない場合 (この種のテーブルの場合、重要ではない可能性があります)、MyISAM を使用するのは簡単なことではありません。date
DATE(datetime)
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
に置き換えることもできます(InnoDB でも機能する別の方法は、 、しかし、ビューは更新も挿入もできないため、ステートメントにのみ役立ちます):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;