適切に正規化されているため、1 つのテーブルを使用するのが適切です。新しいイベント タイプを追加しても、新しいテーブルは必要ありません。また、参照整合性を維持し、インデックスを使用してユーザーのすべてのイベントを取得およびソートすることも、はるかに簡単です。(それらが別々のテーブルにある場合、ユーザーのすべてのイベントを取得して時間順に並べ替えると、1 つのテーブルを使用するよりもはるかに遅くなる可能性があります!)
ただし、スペースを節約し、インデックスを小さく保つために、これらのテーブルを小さくする方法があります。
- を使用し
enum()
て、イベント タイプを定義します。イベントの数が少ない場合は、行ごとに最大 1 バイトを使用します。
UNSIGNED
整数型を使用して、同じバイト数からより多くの sEventID
を取得します。UserID
- 日付の全範囲が必要ない場合 (おそらく)、TIMESTAMP 型を使用して、DATETIME 型と比較して行あたり 4 バイトを節約します。
- ipv4 アドレスのみを使用している場合は、IP を符号なしの 4 バイト整数として保存し、INET_ATON() と INET_NTOA() を使用して相互に変換します。これが最大の勝者です。VARCHAR 型は少なくとも 16 バイト必要であり、固定行長形式を使用できる可能性があります。
次のような表形式をお勧めします。
CREATE TABLE Events (
`EventID` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
`UserID` MEDIUMINT UNSIGNED NOT NULL COMMENT 'this allows a bit more than 16 million users, and your indexes will be smaller',
`EventType` ENUM('add','delete','share') NOT NULL,
`Time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`IP` INTEGER UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (`EventID`),
FOREIGN KEY (`UserID`) REFERENCES `Users` (`UserId`) ON UPDATE CASCADE ON DELETE CASCADE,
KEY (UserID)
);
これを MyISAM を使用して保存すると、行の長さは固定形式を使用して 16 バイトになります。これは、100 万行ごとにデータ用に 16MB のスペースが必要であり、おそらくその半分がインデックス用に必要であることを意味します (使用するインデックスによって異なります)。これは非常にコンパクトであるため、ほとんどの場合、mysql はおそらくテーブルの作業部分全体をメモリ内に保持できます。
次に、最も一般的な操作に必要なインデックスを作成する問題です。たとえば、特定の時間範囲内のすべてのユーザーのイベントを常に表示する場合は、 に置き換えKEY (UserID)
ますINDEX userbytime (UserID, Time)
。次に、次のようなクエリはSELECT * FROM Events WHERE UserID=? AND Time BETWEEN ? AND ?
非常に高速になります。