Frage

In meiner Freizeit begann ich mit einem Datenbank-Backend ein kleines Multiplayer-Spiel zu schreiben. Ich war auf der Suche Spieler Login-Informationen von anderen in Spielinformationen (Inventar, Statistiken und Status) zu trennen und ein Freund brachte dies vielleicht nicht die beste Idee.

Wäre es besser, alles in einer Tabelle einen Topf zu werfen?

War es hilfreich?

Lösung

Starten Sie durch Leistung zu ignorieren, und erstellen Sie einfach die logischste und leicht zu verstehende Datenbank-Design, die Sie können. Wenn Spieler und Spielobjekte (Schwerter? Schachfiguren?) Getrennte Dinge konzeptionell, dann legt sie in separaten Tabellen. Wenn ein Spieler tragen kann, setzen Sie einen Fremdschlüssel in der „Dinge“ Tabelle, die die „Spieler“ Tabelle verweist. Und so weiter.

Wenn Sie dann Hunderte von Spielern und Tausende von Dingen haben, und die Spieler herumlaufen im Spiel und tun Dinge, die Datenbankrecherchen benötigen, na ja, Ihr Design noch schnell genug sein, um, wenn Sie nur die entsprechenden Indizes hinzuzufügen.

Natürlich, wenn Sie sich für Tausende von gleichzeitigen Spielern planen, jeder von ihnen Inventarisierung seine Sachen jede Sekunde, oder vielleicht einige andere enorme Belastung von Datenbankrecherchen (eine Suche nach jedem von der Grafik-Engine gerendert Rahmen?), Dann werden Sie brauchen über die Leistung zu denken. Aber in diesem Fall eine typische Disk-basierte relationale Datenbank nicht schnell genug sein, um wie auch immer, egal, wie Sie Ihre Tabellen entwerfen.

Andere Tipps

Relationale Datenbanken arbeitet auf Sets, eine Datenbankabfrage gibt keine zu liefern ist ( „nicht gefunden“) oder mehr Ergebnisse. Eine relationale Datenbank ist nicht immer genau ein Ergebnis liefern soll durch Ausführen einer Abfrage (über die Beziehungen).

Sagte, dass ich erwähnen möchte, dass das wirkliche Leben ist auch ;-). Eine Eins-zu-Eins-Beziehung Macht Sinn machen, das heißt, wenn die Spaltenanzahl der Tabelle ein kritisches Niveau erreicht hat, kann er schneller sein, um diese Tabelle zu teilen. Aber diese Art von Bedingungen sind wirklich selten.

Wenn Sie nicht wirklich brauchen, um die Tabelle zu spalten nur tut es nicht. Mindestens Ich gehe davon aus, dass in Ihrem Fall würden Sie eine Auswahl über zwei Tabellen zu tun haben, um alle Daten zu bekommen. Dies ist wahrscheinlich langsamer als alle in einer Tabelle gespeichert werden. Und Ihre Programmierlogik wird zumindest ein bisschen weniger lesbar erhalten, indem dies zu tun.

Edith sagt: : auf Normalisierung Kommentar: Nun, ich sah nie eine Datenbank, um es normalisiert ist max und niemand wirklich empfiehlt, dass als Option. Wie auch immer, wenn Sie nicht genau wissen, ob alle Spalten normiert werden (dh in anderen Tabellen setzen) später, dann auch es einfacher ist, diese anstelle von „Tisch“ -on-to-Ein- "anderer Tabelle mit einer Tabelle zu tun „

Ob halten

  

Spieler Login-Informationen [getrennt] von anderen in   Spielinformationen (Inventar, Statistiken,   und Status)

ist oft eine Frage der Normalisierung. Sie können einen kurzen Blick auf die wikipedia nehmen wollen ( dritten Normalform , Denormalisierung ) Definitionen. Egal, ob Sie diese in mehrere Tabellen trennen hängt davon ab, welche Daten gespeichert werden. Erweitern Sie Ihre Frage wird diese konkretisieren. Daten, die wir speichern wollen, ist:

  • Benutzername: eindeutigen Namen, die ein Benutzer in das System einloggen können
  • passwd: Passwort: mit dem Benutzernamen zugeordnet, die den Benutzer gewährleistet ist einzigartig
  • E-Mail: E-Mail-Adresse für den Benutzer; so kann das Spiel „Poke“ den Benutzer, wenn sie nicht vor kurzem gespielt haben
  • Charakter: möglicherweise getrennter Ingame-Name für den Charakter
  • Status: ist der Spieler und / oder Zeichen zur Zeit aktiven
  • Hitpoints: ein Beispiel stat für das Zeichen

Wir können speichern diese als eine einzige Tabelle oder als mehrere Tabellen.

Single Table Beispiel

Wenn die Spieler ein einzelnes Zeichen in dieser Spielwelt haben, dann eine einzige Tabelle geeignet sein kann. Zum Beispiel:

CREATE TABLE players(
  id         INTEGER NOT NULL,
  username   VARCHAR2(32) NOT NULL,
  password   VARCHAR2(32) NOT NULL,
  email      VARCHAR2(160),
  character  VARCHAR2(32) NOT NULL,
  status     VARCHAR2(32),
  hitpoints  INTEGER,

  CONSTRAINT pk_players PRIMARY KEY (uid)
);

Auf diese Weise könnten Sie alle relevanten Informationen zu einem Spieler mit einer einzigen Abfrage auf der Spieler-Tabelle zu finden.

Mehrere Tabelle Beispiel

Wenn Sie jedoch ein einzelner Spieler ermöglichen, wollte man diese Daten auf zwei verschiedenen Tabellen möchte mehrere verschiedene Charaktere haben, teilen. Zum Beispiel könnten Sie Folgendes tun:

-- track information on the player
CREATE TABLE players(
  id         INTEGER NOT NULL,
  username   VARCHAR2(32) NOT NULL,
  password   VARCHAR2(32) NOT NULL,
  email      VARCHAR2(160),

  CONSTRAINT pk_players PRIMARY KEY (id)
);

-- track information on the character
CREATE TABLE characters(
  id         INTEGER NOT NULL,
  player_id  INTEGER NOT NULL,
  character  VARCHAR2(32) NOT NULL,
  status     VARCHAR2(32),
  hitpoints  INTEGER,

  CONSTRAINT pk_characters PRIMARY KEY (id)
);
-- foreign key reference
ALTER TABLE characters
  ADD CONSTRAINT characters__players
  FOREIGN KEY (player_id) REFERENCES players (id);

Dieses Format verbindet benötigt, wenn an Informationen sowohl für den Spieler und Charakter suchen; macht es jedoch Aktualisierung Aufzeichnungen weniger wahrscheinlich, dass in Inkonsistenz führen. Dieses Argument wird normalerweise verwendet, wenn für mehrere Tabellen befürworten. Zum Beispiel, wenn Sie einen Spieler (LOTRfan) mit zwei Zeichen (Gollum, frodo) in dem einzelnen Tabellenformat haben würden Sie die Benutzername, Passwort, E-Mail-Felder dupliziert haben. Wenn der Spieler sein E-Mail / Passwort ändern wollte, müßten Sie beiden Datensätze ändern. Wenn nur ein Datensatz der Tabelle geändert wurde, wird inkonsistent werden. Wenn jedoch LOTRfan sein Passwort in mehrere Tabellenformat zu ändern, um eine einzelne Zeile in der Tabelle aktualisiert wird gesucht.

Andere Überlegungen

Ob eine einzelne Tabelle oder mehrere Tabellen zu verwenden, hängt von den zugrunde liegenden Daten. Was hier nicht beschrieben, sondern in anderen Antworten darauf hingewiesen, dass Optimierungen oft zwei Tabellen nehmen und sie in eine einzige Tabelle kombinieren.

Auch von Interesse ist, die Arten von Änderungen zu wissen, die gemacht werden. Zum Beispiel, wenn Sie sind zu wählen, eine einzelne Tabelle für die Spieler zu verwenden, die mehrere Charaktere haben könnten und wollten den Überblick über Gesamtzahl der Befehle durch den Spieler ausgegeben halten, indem ein Feld in der Tabelle Spieler erhöht wird; dies würde zu mehr Zeilen in dem einzigen Tabelle Beispiel aktualisiert werden.

Inventory ist ein Viele-zu-Eins-Beziehung sowieso, also wahrscheinlich verdient eine eigene Tabelle (indexiert auf ihrer Fremdschlüssel zumindest).

Sie können auch für jeden Benutzer von öffentlichen Sachen trennen persönliche Sachen haben (das heißt, was andere können Sie sehen). Das kann eine besseren Cache-Treffer liefern, da viele Menschen Ihre öffentlichen Attribute sehen, aber nur Sie Ihre persönlichen Eigenschaften sehen.

A 1-1 Beziehung ist nur eine vertikale Teilung. Nichts anderes. wenn Sie es aus irgendeinem Grund werden Sie nicht alle Daten in derselben Tabelle speichern (etwa für die Partitionierung über mehrere Server usw.)

Wie Sie sehen können, auf das der allgemeine Konsens ist, dass „es kommt“. Leistung / Abfrageoptimierung kommt leicht in den Sinn -. Wie durch @Campbell und andere erwähnt

Aber ich denke, für die Art von anwendungsspezifischen Datenbank, die Sie bauen, ist es am besten unter Berücksichtigung der gesamten Anwendungsdesign zu starten. Für anwendungsspezifische Datenbanken (im Gegensatz zu Datenbanken im Gegensatz entwickelt, um mit vielen Anwendungen oder Reporting-Tool verwendet werden), das ‚ideales‘ Datenmodell ist wahrscheinlich derjenige, die besten Karten zu Ihrem Domain-Modell wie in dem Anwendungscode implementiert.

Sie können nicht Ihr Design nennen MVC , und ich weiß nicht wissen, welche Sprache Sie verwenden, aber ich erwarte, dass Sie einen Code oder Klassen, die den Datenzugriff mit einem logischen Modell umschließt. Wie Sie das Anwendungsdesign auf dieser Ebene sehen ist, ich denke, der beste Indikator dafür, wie Ihre Datenbank sollte ideal strukturiert werden.

In der Regel bedeutet dies eine Eins-zu-Eins-Abbildung von Domänenobjekten auf Datenbanktabellen ist der beste Ort zu beginnen.

Ich denke, am besten zu veranschaulichen, was ich mit gutem Beispiel bedeuten:

Fall 1: Eine Klasse / Eine Tabelle

Sie denken in einer Spieler Klasse. Player.authenticate, Player.logged_in ?, Player.status, Player.hi_score, Player.gold_credits. Solange all diese Aktionen auf einem einzelnen Benutzer oder Einzelwert-Attribute eines Benutzers repräsentiert, dann eine einzige Tabelle sollte Ihr Ausgangspunkt von einer logischen Anwendungsdesign Perspektive sein. Einzel Klasse (Player), einzelne Tabelle (Spieler).

Fall 2: Mehrere Klasse / Eine oder mehr Tabellen

Vielleicht Ich mag nicht das Schweizer Taschenmesser Spieler Klasse Design, bevorzugen aber in Bezug auf Benutzer zu denken, , Inventar Anzeiger und Konto . User.authenticate, User.logged_in ?, User-> account.status, Scoreboard.hi_score (Benutzer), User-> account.gold_credits.

Ich tue dies wahrscheinlich, weil ich denke, diese Konzepte in der Domänenmodell Trennung wird zu meinen Code übersichtlicher und einfacher zu schreiben machen. In diesem Fall ist der beste Ausgangspunkt eine direkte Zuordnung der Domain-Klassen zu einzelnen Tabellen:. Benutzer, Inventar, Ergebnisse, Konten usw.

Making the 'Ideal' Practical

Ich rutschte ein paar Worte in oben, um anzuzeigen, dass die Ein-Eins-Zuordnung von Domain-Objekten zu Tabellen ist die ideal, logische Design.

Das ist mein bevorzugter Ausgangspunkt. Der Versuch, von der Fledermaus zu sein, zu klug - mehrere Klassen wieder zu einer einzigen Tabelle wie die Abbildung - neigt dazu, nur Ärger lädt ich lieber zu vermeiden (Deadlocks und Parallelität Probleme vor allem)

.

Aber es ist nicht immer das Ende der Geschichte. Es gibt praktische Überlegungen, die eine selbständige Tätigkeit bedeuten kann das physische Datenmodell zur Optimierung benötigt wird, z.B. Gleichzeitigkeit / Probleme mit Sperren? Zeilengröße zu groß wird? Indizierung Overhead? Abfrageleistung etc.

Seien Sie vorsichtig, wenn zwar über Leistung denken: nur weil es in einer Tabelle eine Zeile sein kann, wahrscheinlich bedeutet nicht, es nur einmal abgefragt wird, um die ganze Reihe zu bekommen. Ich stelle mir das Multi-User-Spielszenario eine ganze Reihe von Anrufen beinhalten kann unterschiedliche Spieler Informationen zu verschiedenen Zeiten zu bekommen, und die Spieler wollen immer den ‚aktuellen Wert‘, die sehr dynamisch sein können. Das kann nur für ein paar Spalten in der Tabelle jedes Mal (in diesem Fall, ein Multi-Table-Design könnte schneller als ein Single-Table-Design).

in viele Anrufe übersetzen

Ich empfehle ihnen zu trennen. Nicht für alle Datenbank Gründe, sondern für die Entwicklung Gründe.

Wenn Sie Ihre Spieler-Login-Modul-Codierung, Sie möchten nicht über eine der Spielinformationen denken. Und umgekehrt. Es wird leichter sein, eine Trennung von Bedenken zu halten, wenn die Tabellen verschieden sind.

Es läuft darauf hinaus auf die Tatsache, dass Ihr Spiel Informationsmodul nicht kein Geschäft messin' bekommt ist um mit der Spieler Login-Tabelle.

Wahrscheinlich auch in dieser Situation in einer Tabelle setzen als die Abfrageleistung besser sein wird.

Sie wollen wirklich nur auf den nächsten Tisch verwenden, wenn es ein Element der doppelten Daten sein, mit denen Sie zu einer Normalisierung aussehen sollten Ihre Datenspeichergemeinkosten zu reduzieren.

Ich stimme mit Thomas Padron-McCarthy Antwort :

Solving für den Fall von Tausenden von Benutzern gleichzeitig ist nicht Ihr Problem. Erste Menschen um Ihr Spiel zu spielen, ist das Problem. Beginnen Sie mit der einfachsten Ausführung - Holen Sie sich das Spiel getan, arbeiten, spielbar und einfach erweiterbar. Wenn das Spiel auszieht, dann entnormalisiert Sie.

Es ist auch erwähnenswert, dass Indizes können als separate Tabellen betrachtet werden, die eine engere Sicht auf die Daten enthalten.

Die Menschen waren in der Lage ein Design von Blizzard für World of Warcraft verwendet abzuleiten. Es scheint, dass die Quests ein Spieler auf dem Charakter gespeichert wird. z.

CREATE TABLE Players (
   PlayerID int,
   PlayerName varchar(50),
   ...
   Quest1ID int,
   Quest2ID int,
   Quest3ID int,
   ...
   Quest10ID int,
   ...
)

Zunächst Sie auf höchstens 10 Aufgaben sein könnten, später es wurde auf 25 erweitert, z.

CREATE TABLE Players (
   PlayerID int,
   PlayerName varchar(50),
   ...
   Quest1ID int,
   Quest2ID int,
   Quest3ID int,
   ...
   Quest25ID int,
   ...
)

Dies ist im Gegensatz zu einer Split-Ausführung:

CREATE TABLE Players (
   PlayerID int,
   PlayerName varchar(50),
   ...
)

CREATE TABLE PlayerQuests (
   PlayerID int,
   QuestID int
)

Letzteres ist viel einfacher, konzeptionell zu behandeln, und es erlaubt die beliebige Anzahl von Aufgaben. Auf der anderen Seite haben Sie Spieler und PlayerQuests zu verbinden, um all diese Informationen zu erhalten.

Ich würde vorschlagen, dass Sie in einer eigenen Tabelle, die jeden Satztyp halten.

Spieler Logins ist eine Art der Aufzeichnung. Inventar ist eine andere. Sie sollten nicht einen Tisch teilen, wie die meisten Informationen nicht geteilt wird. Halten Sie Ihre Tabellen einfach durch unabhängige Informationen abscheidet.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top