このすばらしいNettuts+の記事のヒントを読んだ後、大量の読み取りが行われる他のテーブルから非常に揮発性の高いデータを分離し、同時にデータベーススキーマ全体で必要なテーブルの数を減らすテーブルスキーマを思いつきました。正規化のルールに従わないため、これが良いアイデアかどうかはわかりません。アドバイスを聞きたいのですが、一般的なアイデアは次のとおりです。
クラステーブル継承構造でモデル化された4種類のユーザーがあり、メインの「ユーザー」テーブルに、すべてのユーザーに共通のデータ(id
、、、、いくつかusername
、...)といくつかのフィールド( 、、、、、、)を格納します。 ..)。password
flags
TIMESTAMP
date_created
date_updated
date_activated
date_lastLogin
上記のNettuts+の記事からヒント#16を引用するには:
例2:テーブルに「last_login」フィールドがあります。ユーザーがWebサイトにログインするたびに更新されます。ただし、テーブルを更新するたびに、そのテーブルのクエリキャッシュがフラッシュされます。そのフィールドを別のテーブルに配置して、ユーザーテーブルの更新を最小限に抑えることができます。
今ではさらにトリッキーになります。次のようなユーザー統計を追跡する必要があります。
- ユーザープロファイルが表示された一意の回数
- 特定のタイプのユーザーの広告がクリックされたユニークな回数
- 特定のタイプのユーザーからの投稿が表示されたユニークな回数
- 等々...
私の完全に正規化されたデータベースでは、これにより約8〜10個の追加テーブルが追加されます。それほど多くはありませんが、できれば単純にしておきたいので、次の" events
"テーブルを作成しました。
|------|----------------|----------------|---------------------|-----------|
| ID | TABLE | EVENT | DATE | IP |
|------|----------------|----------------|---------------------|-----------|
| 1 | user | login | 2010-04-19 00:30:00 | 127.0.0.1 |
|------|----------------|----------------|---------------------|-----------|
| 1 | user | login | 2010-04-19 02:30:00 | 127.0.0.1 |
|------|----------------|----------------|---------------------|-----------|
| 2 | user | created | 2010-04-19 00:31:00 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 2 | user | activated | 2010-04-19 02:34:00 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 2 | user | approved | 2010-04-19 09:30:00 | 217.0.0.1 |
|------|----------------|----------------|---------------------|-----------|
| 2 | user | login | 2010-04-19 12:00:00 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 15 | user_ads | created | 2010-04-19 12:30:00 | 127.0.0.1 |
|------|----------------|----------------|---------------------|-----------|
| 15 | user_ads | impressed | 2010-04-19 12:31:00 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 15 | user_ads | clicked | 2010-04-19 12:31:01 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 15 | user_ads | clicked | 2010-04-19 12:31:02 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 15 | user_ads | clicked | 2010-04-19 12:31:03 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 15 | user_ads | clicked | 2010-04-19 12:31:04 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 15 | user_ads | clicked | 2010-04-19 12:31:05 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 2 | user | blocked | 2010-04-20 03:19:00 | 217.0.0.1 |
|------|----------------|----------------|---------------------|-----------|
| 2 | user | deleted | 2010-04-20 03:20:00 | 217.0.0.1 |
|------|----------------|----------------|---------------------|-----------|
基本的に、はテーブルID
の主キー(id
)フィールドを指しTABLE
ますが、残りはかなり簡単なはずです。この設計で私が気に入った点の1つは、最後のログインだけでなく、すべてのユーザーログインを追跡できるため、そのデータを使用していくつかの興味深いメトリックを生成できることです。
テーブルの性質が大きくなっているためevents
、次のようないくつかの最適化を行うことも考えました。
- #9:有限数のテーブルと有限(および所定の)数のイベントしかないため、スペースを節約するために、
TABLE
および列をsではなくsEVENTS
として設定できます。ENUM
VARCHAR
- #14:
IP
sをUNSIGNED INT
sの代わりINET_ATON()
にsとして保存しVARCHAR
ます。 - s
DATE
をTIMESTAMP
sではなくsとして保存しDATETIME
ます。 - /の代わりに
ARCHIVE
(または)エンジンを使用します。CSV
?InnoDB
MyISAM
INSERT
sとsのみSELECT
がサポートされており、データはその場で圧縮されます。
全体として、各イベントは14(非圧縮)バイトしか消費しません。これは私のトラフィックには問題ないと思います。
長所:
- より詳細なデータ(ログインなど)を保存する機能。
- ほぼ12個の追加のテーブル(日付と統計)を設計(およびコーディング)する必要はありません。
- テーブルごとに数列を削減し、揮発性データを分離します。
短所:
- 非リレーショナル(まだEAVほど悪くはない):
SELECT * FROM events WHERE id = 2 AND table = 'user' ORDER BY date DESC();
- イベントごとに6バイトのオーバーヘッド(、、
ID
およびTABLE
)EVENT
。
長所が短所をはるかに上回っているように見えるので、私はこのアプローチを採用する傾向がありますが、それでも私は少し気が進まない...何かが足りないのですか?これについてどう思いますか?
ありがとう!
@coolgeek:
私が少し違うことの1つは、entity_typeテーブルを維持し、そのIDをobject_type列(この場合は「TABLE」列)で使用することです。event_typeテーブルでも同じことをしたいと思うでしょう。
明確にするために、テーブルで許可されるイベントをマップするテーブルを追加し、TABLE
/EVENT
ペアを使用する代わりにイベントテーブルでそのテーブルのPKを使用する必要があることを意味しますか?
@ben:
これらはすべて既存のデータから得られた統計ですよね?
追加のテーブルは主に統計に関連していますが、データはまだ存在していません。いくつかの例を示します。
user_ad_stats user_post_stats
------------- ---------------
user_ad_id (FK) user_post_id (FK)
ip ip
date date
type (impressed, clicked)
これらのテーブルを削除すると、誰が、何を、いつ、ビューがここでどのように役立つかを追跡する方法がありません。
私はそれが分離されるべきであることに同意しますが、それは根本的に異なるデータであるためです。誰かが何であるか、そして誰かが何をするかは、2つの異なることです。ボラティリティはそれほど重要ではないと思います。
私はそれを両方の方法で聞いたが、MySQLのマニュアルにはどちらかが正しいと述べているものは何も見つからなかった。とにかく、それらはデータの種類を表すため、別々のテーブルにする必要があることに同意します(通常のアプローチよりも説明的であるという追加の利点があります)。
いわば、木々の森が欠けていると思います。
テーブルの述語は「DATEEVENTEDTOTABLEの時点でのIPIPからのユーザーID」であり、妥当と思われますが、問題があります。
「EAVほど悪くない」という意味は、すべてのレコードが線形構造に従っていて、クエリが非常に簡単であるということです。階層構造がないため、すべてのクエリを単純なで実行できますSELECT
。
あなたの2番目の声明に関して、あなたは私をここで間違って理解したと思います。IPアドレスは必ずしもユーザーに関連付けられているとは限りません。テーブル構造は次のようになります。
IPアドレス( )は、日付()にテーブル( )のPK()に対して
IP
何か( )を実行しました。EVENT
ID
TABLE
DATE
たとえば、上記の例の最後の行では、IP 217.0.0.1(一部の管理者)が2010-04-20 03:20:00にユーザー#2(最後の既知のIPは127.0.0.2)を削除したことを示しています。 。
たとえば、ユーザーイベントをユーザーに参加させることはできますが、外部キー制約を実装することはできません。
確かに、それが私の主な関心事です。ただし、従来のリレーショナルデザインではうまくいかなかったこのデザインで、何がうまくいかないのか完全にはわかりません。いくつかの注意点を見つけることができますが、データベースをいじっているアプリがそれが何をしているのかを知っている限り、問題はないはずです。
この議論で重要なもう1つのことは、私がはるかに多くのイベントを保存することです。各イベントは元の設計と比較して2倍以上になります。ここでストレージエンジンを使用することは完全に理にかなっていますがARCHIVE
、唯一のことはそうではないということです。 sをサポートしますFK
(UPDATE
sでもDELETE
sでもありません)。