Database - Entwerfen einer Ereignistabelle

Nach dem Lesen der Tipps vondieses tolle Nettuts + article Ich habe mir ein Tabellenschema ausgedacht, mit dem hochflüchtige Daten von anderen Tabellen, die starken Lesevorgängen ausgesetzt sind, getrennt und gleichzeitig die Anzahl der im gesamten Datenbankschema benötigten Tabellen verringert werden können. Ich bin mir jedoch nicht sicher, ob dies ein solches Schema ist Gute Idee, da es nicht den Regeln der Normalisierung folgt und ich Ihren Rat gerne höre, hier ist die allgemeine Idee:

Ich habe vier Arten von Benutzern in einem @ modellieClass Table Inheritance Struktur, in der Haupttabelle "Benutzer" speichere ich Daten, die allen Benutzern gemeinsam sind id, username, password, mehrereflags, ...) zusammen mit einigenTIMESTAMP Felder date_created, date_updated, date_activated, date_lastLogin, ...).

Um den Tipp # 16 aus dem oben erwähnten Artikel Nettuts + zu zitieren:

Beispiel 2: Sie haben ein "last_login" -Feld in Ihrer Tabelle. Es wird jedes Mal aktualisiert, wenn sich ein Benutzer auf der Website anmeldet. Bei jeder Aktualisierung einer Tabelle wird jedoch der Abfragecache für diese Tabelle geleert. Sie können dieses Feld in eine andere Tabelle einfügen, um die Aktualisierung Ihrer Benutzertabelle auf ein Minimum zu beschränken.

Nun wird es noch kniffliger, ich muss einige Benutzerstatistiken wie @ nachverfolg

wie vieleeinzigarti mal wurde ein Benutzerprofil gesehenwie vieleeinzigarti mal einad von einemspezifischer Benutzertyp wurde angeklicktwie vieleeinzigarti mal einpost von einemspezifischer Benutzertyp wurde geseheund so weiter..

In meiner vollständig normalisierten Datenbank summieren sich dies auf ungefähr 8 bis 10 zusätzliche Tabellen. Es ist nicht viel, aber ich würde gerne die Dinge einfach halten, wenn ich könnte, also habe ich mir Folgendes ausgedacht "events" Tabelle

|------|----------------|----------------|---------------------|-----------|
| 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 |
|------|----------------|----------------|---------------------|-----------|

rundsätzlich dieID bezieht sich auf den Primärschlüssel id) Feld imTABLEtable, ich glaube der Rest sollte ziemlich unkompliziert sein. Eine Sache, die mir an diesem Design gefallen hat, ist, dass ich alle Benutzeranmeldungen und nicht nur die letzten nachverfolgen und auf diese Weise einige interessante Metriken mit diesen Daten generieren kann.

Aufgrund der wachsenden Natur desevents table Ich habe mir auch überlegt, einige Optimierungen vorzunehmen, zum Beispiel:

# 9: Da es nur eine endliche Anzahl von Tabellen und eine endliche (und vorgegebene) Anzahl von Ereignissen gibt, wird dasTABLE undEVENTS Spalten können als @ eingerichtet werdENUMs stattVARCHARs, um Platz zu sparen. # 14: GeschäftIPs alsUNSIGNED INTs mitINET_ATON() Anstatt vonVARCHAR s.GeschäftDATEs alsTIMESTAMPs Anstatt vonDATETIME s.Verwende dasARCHIVE (oder derCSV?) Motor anstelle vonInnoDB / MyISAM.NurINSERTs undSELECTs werden unterstützt und Daten werden im laufenden Betrieb komprimiert.

nsgesamt würde jedes Ereignis nur 14 (unkomprimierte) Bytes verbrauchen, was für meinen Datenverkehr in Ordnung is

Pros: Möglichkeit, detailliertere Daten (wie Anmeldungen) zu speichern. Keine Notwendigkeit zu entwerfen und Code für) Fast ein Dutzend zusätzliche Tabellen (Daten und Statistiken). Reduziert einige Spalten pro Tabelle und hält flüchtige Daten getrennt.Cons: Nicht relational (immer noch nicht so schlecht wie EAV):SELECT * FROM events WHERE id = 2 AND table = 'user' ORDER BY date DESC(); 6 Byte Overhead pro Ereignis ID, TABLE undEVENT).

Ich bin eher geneigt, diesen Ansatz zu wählen, da die Vorteile die Nachteile bei weitem überwiegen, aber ich bin immer noch ein bisschen zurückhaltend ... Bin ich etwas vermisst? Was denkst du darüber?

Vielen Dank

@ coolgeek:

Eine Sache, die ich etwas anders mache, besteht darin, eine Entity_Type-Tabelle zu verwalten und ihre ID in der Object_Type-Spalte (in Ihrem Fall die 'TABLE'-Spalte) zu verwenden. Sie möchten dasselbe mit einer event_type-Tabelle tun.

Um ganz klar zu sein, ich sollte eine zusätzliche Tabelle hinzufügen, die die in einer Tabelle zulässigen Ereignisse abbildet, und die PK dieser Tabelle in der Ereignistabelle verwenden, anstatt ein @ zu habeTABLE / EVENT Paar

@ ben:

Das sind alles Statistiken, die aus vorhandenen Daten abgeleitet wurden, nicht wahr?

Die zusätzlichen Tabellen beziehen sich hauptsächlich auf Statistiken, die Daten sind jedoch noch nicht vorhanden, einige Beispiele:

user_ad_stats                          user_post_stats
-------------                          ---------------
user_ad_id (FK)                        user_post_id (FK)
ip                                     ip
date                                   date
type (impressed, clicked)

Wenn ich diese Tabellen fallen lasse, kann ich nicht nachverfolgen, wer, was oder wann, nicht sicher, wie Ansichten hier helfen können.

Ich stimme zu, dass es separat sein sollte, aber mehr, weil es sich um grundlegend unterschiedliche Daten handelt. Was jemand ist und was jemand tut, sind zwei verschiedene Dinge. Ich denke nicht, dass Volatilität so wichtig ist.

Ich habe es in beide Richtungen gehört und konnte im MySQL-Handbuch nichts finden, was besagt, dass eines der beiden richtig ist. Wie auch immer, ich stimme Ihnen zu, dass sie getrennte Tabellen sein sollten, da sie Arten von Daten darstellen (mit dem zusätzlichen Vorteil, dass sie aussagekräftiger sind als ein regulärer Ansatz).

Ich denke, du vermisst den Wald vor lauter Bäumen sozusagen.

Das Prädikat für Ihre Tabelle lautet "Benutzer-ID von IP-Adresse zum Zeitpunkt des EREIGNISDATUMS bis TABELLE", was vernünftig erscheint, aber es gibt Probleme.

Was ich mit "nicht so schlecht wie EAV" meinte, ist, dass alle Datensätze einer linearen Struktur folgen und dass sie ziemlich einfach abzufragen sind. Es gibt keine hierarchische Struktur, so dass alle Abfragen mit einem einfachen @ durchgeführt werden könneSELECT.

ezüglich Ihrer zweiten Aussage denke ich, dass Sie mich hier falsch verstanden haben. Die IP-Adresse muss nicht unbedingt dem Benutzer zugeordnet sein. Die Tabellenstruktur sollte ungefähr so lauten:

IP Adresse IP) Tat etwas EVENT) an die PK ID) des Tisches TABLE) am Datum DATE).

In der letzten Zeile meines obigen Beispiels sollte beispielsweise lauten, dass IP 217.0.0.1 (einige Administratoren) den Benutzer # 2 (dessen letzte bekannte IP 127.0.0.2 ist) am 2010-04-20 03:20 gelöscht hat: 00.

Sie können weiterhin Benutzerereignisse mit Benutzern verknüpfen, aber keine Fremdschlüsseleinschränkung implementieren.

Indeed, das ist mein Hauptanliegen. Ich bin mir jedoch nicht ganz sicher, was mit diesem Design schief gehen kann, das mit einem traditionellen relationalen Design nicht schief gehen kann. Ich kann einige Vorbehalte erkennen, aber solange die App weiß, was sie mit der Datenbank macht, sollte es keine Probleme geben.

Eine andere Sache, die in diesem Argument zählt, ist, dass ich viel mehr Ereignisse speichere und jedes Ereignis mehr als doppelt so groß ist wie das ursprüngliche Design. Es ist absolut sinnvoll, das @ zu verwendeARCHIVE Speicher-Engine hier, das einzige, was es nicht unterstütztFKs (wederUPDATEs oderDELETEs).

Antworten auf die Frage(3)

Ihre Antwort auf die Frage