Hallo,
nachdem das Thema bei uns im Team gerade aufkam, habe ich eine Frage an diejenigen, die sich mit MySql etwas besser auskennen. Im Hinblick auf Praxiserfahrungen in einer Webanwendung wie bsp. einem Browserspiel.
Es geht im Endeffekt um das sinnvolle Einsetzen von Tabellen.
Was ist im Hinblick auf eine performante Anwendung ratsamer?
Einerseits kann man argumentieren, dass alle 1:1-Beziehungen auch in eine Tabelle gehören, was durchaus aber den Datensatz in eine Größenordnung von mehreren Dutzend Spaltendimension bringen kann.
mögliche Proargumente: wesentlich einfachere Handhabung (für Anwender=Entwickler), keine unnötigen Racecondition-Situationen, Readblocks sind "groß" genug, um das Problem, das kaum ein Script mehr als ein Dutzend Spalten benötigt
Andererseits kann man auch argumentieren, dass man nur die Basisdaten, also quasi die überall verwendeten Stammdaten eines Accounts, zentral speichern sollte, aber die Spalten, die nur in wenigen Scripts sowohl schreibend, als auch lesend verfügbar sein müssen, in eine extra Tabelle gespeichert werden. Natürlich verlinkt mit der UserId.
Die Notwendigkeit von korrekter Verwendung von Indizes, Fremdschlüsseln (sofern das überhaupt von Mysql korrekt supported würde) setze ich voraus, das wäre nicht die Frage.
Mögliche Proargumente: Die Abfrage auf die Stammdaten, die in jedem Script erforderlich sind, würden einen kleinen Datensatz betreffen (auch bei Ausführung und Zusammenstellung der Abfrage bzw. Modifizierung). Alle zusätzlichen Daten werden in den Leseprozess nur dann eingebunden, wenn sie überhaupt erforderlich sind.
Was wäre besser? Im Hinblick auf das DB-Layout würde ich persönlich fast ohne zu Zögern auf die erste Variante zeigen, aber es nützt auch nichts, wenn es nicht schnell ist. Vor allem bei einer Webanwendung erwartet der User schnell ein Feedback.. und solange man nicht schummelt - bsp. durch JavaScript-Techniken mit Backends wie wie Ajax - wird der User ein "Warten" im Browser nicht gerne sehen.
Meinungen, Anmerkungen, Links, Benchmarks, Alternativen.. ich höre gerne alles.
Datenbanktabellen in MySql
gepostet vor 17 Jahre, 9 Monate von knalli
gepostet vor 17 Jahre, 9 Monate von exception
Gerade in Bezug auf MyISAM spielen Table-Locks eine große Rolle. Sobald MySQL ein Update auf eine Tabelle ausführt oder ein INSERT in eine Tabelle mit nicht-fixer Spaltenbreite durchführt muss die gesamte Tabelle gesperrt werden.
Je mehr Spalten eine Tabelle hat, desto höher ist das Risiko, dass es zu Locks kommt. Dadurch kann dann vor allem auf Mehrprozessorsystemen nicht mehr die volle Systemleistung genutzt werden.
Bei kleinerer Spaltenzahl ist es außerdem eher möglich, komplett auf fixe Spaltengrößen zu setzen (CHAR() statt VARCHAR()) und dadurch eine fixe Zeilenlänge zu erhalten, was sich positiv auf Performance auswirkt.
Praktisches Beispiel: Stämme Welt 8 war auf ca. 45.000 Spieler begrenzt, wenn wir nicht sehr teure Hardware verwendet hätten oder auf eine andere Datenbankengine umstellen würden. Ursache war vor allem eine hohe Anzahl an Schreibzugriffen auf zentrale Tabellen.
Welt 10 läuft mit einer neuen Version, in der einige sehr große zentrale Tabellen aufgesplittet wurden, und einige Tabellen jetzt auf einem zweiten Datenbankserver liegen (keine Replikation, sondern zwei getrennte DB-Server). Dadurch lief es bis ca. 65k Spieler problemlos und das Limit liegt bei ca. 75k Spielern.
Je mehr Spalten eine Tabelle hat, desto höher ist das Risiko, dass es zu Locks kommt. Dadurch kann dann vor allem auf Mehrprozessorsystemen nicht mehr die volle Systemleistung genutzt werden.
Bei kleinerer Spaltenzahl ist es außerdem eher möglich, komplett auf fixe Spaltengrößen zu setzen (CHAR() statt VARCHAR()) und dadurch eine fixe Zeilenlänge zu erhalten, was sich positiv auf Performance auswirkt.
Praktisches Beispiel: Stämme Welt 8 war auf ca. 45.000 Spieler begrenzt, wenn wir nicht sehr teure Hardware verwendet hätten oder auf eine andere Datenbankengine umstellen würden. Ursache war vor allem eine hohe Anzahl an Schreibzugriffen auf zentrale Tabellen.
Welt 10 läuft mit einer neuen Version, in der einige sehr große zentrale Tabellen aufgesplittet wurden, und einige Tabellen jetzt auf einem zweiten Datenbankserver liegen (keine Replikation, sondern zwei getrennte DB-Server). Dadurch lief es bis ca. 65k Spieler problemlos und das Limit liegt bei ca. 75k Spielern.
gepostet vor 17 Jahre, 9 Monate von COrthbandt
Es macht sicher nicht viel Sinn, die Database bis zur 25. Normalform zu zerpflücken.
Zum Thema Zugriffsgeschwindigkeit: Datenbanken arbeiten meist Page-orientiert. Auf dem durchschnittlichen x86-Server bedeutet das, dass die Daten in Blöcken von 4kB verwaltet werden. Wenn Du also Records von deutlich weniger als 4kB hast, verschwendest Du im Prinzip Performance auf den Fetch von benachbarten aber nicht benötigten Rows der gleichen Table.
Das heisst natürlich nicht, dass es Sinn machen würde, eine Row auf 4kB aufzublasen. Es relativiert nur die Zweckhaftigkeit einer übertriebenen Unterteilung.
Ein wesentliches Kriterium bei den Locks ist die Concurrency. Wenn Du Deine Daten so aufteilen kannst, dass Du einen nur vom Spieler modifizier- und/oder sichtbaren Bereich (Bauqueue z.B.) und einen quasi öffentlichen (Anzahl Einwohner udgl), dann hilft das beim Locking ungemein.
Gerade dann ist natürlich auch zu berücksichtigen, dass es eher die Ausnahme sein dürfte, dass ein Spieler auf seine privaten Daten hochparallel zugreift. Es sei denn, er ist ein fieser Bot oder Account-Sharer.
Latency Hiding, Client Side Prediction und Dead Reckoning sind für Dich eventuell interessante Techniken, die bei Non-Web-Multiplayer-Games zwingend sind, um die Verzögerungen erträglicher oder ganz unsichtbar zu machen. AJAX ist da ganz sicher ein sinnvoller Ansatz.
Im Prinzip ist solche Optimierung von zwei Seiten anzugehen:
1. Reduktion der Server-Last
2. Reduktion des wahrgenommenen Lags
1) kannst Du durchaus mit Optimierung Deiner DB erreichen. Aber mit 250-1500 ms Delay musst Du immer rechnen und dann hilft 2) wesentlich weiter. Es gibt einige Studien (sorry, keine Links da) die zeigen, dass ein sofortiger Response mit Verzögerung der realen Ergebnisse immer vorzuziehen ist, selbst wenn ein kompletter Response doppelt so schnell wäre.
Das war jetzt alles ein bischen durcheinander, aber ich hoffe es ist irgendwie hilfreich...
Zum Thema Zugriffsgeschwindigkeit: Datenbanken arbeiten meist Page-orientiert. Auf dem durchschnittlichen x86-Server bedeutet das, dass die Daten in Blöcken von 4kB verwaltet werden. Wenn Du also Records von deutlich weniger als 4kB hast, verschwendest Du im Prinzip Performance auf den Fetch von benachbarten aber nicht benötigten Rows der gleichen Table.
Das heisst natürlich nicht, dass es Sinn machen würde, eine Row auf 4kB aufzublasen. Es relativiert nur die Zweckhaftigkeit einer übertriebenen Unterteilung.
Ein wesentliches Kriterium bei den Locks ist die Concurrency. Wenn Du Deine Daten so aufteilen kannst, dass Du einen nur vom Spieler modifizier- und/oder sichtbaren Bereich (Bauqueue z.B.) und einen quasi öffentlichen (Anzahl Einwohner udgl), dann hilft das beim Locking ungemein.
Gerade dann ist natürlich auch zu berücksichtigen, dass es eher die Ausnahme sein dürfte, dass ein Spieler auf seine privaten Daten hochparallel zugreift. Es sei denn, er ist ein fieser Bot oder Account-Sharer.
Latency Hiding, Client Side Prediction und Dead Reckoning sind für Dich eventuell interessante Techniken, die bei Non-Web-Multiplayer-Games zwingend sind, um die Verzögerungen erträglicher oder ganz unsichtbar zu machen. AJAX ist da ganz sicher ein sinnvoller Ansatz.
Im Prinzip ist solche Optimierung von zwei Seiten anzugehen:
1. Reduktion der Server-Last
2. Reduktion des wahrgenommenen Lags
1) kannst Du durchaus mit Optimierung Deiner DB erreichen. Aber mit 250-1500 ms Delay musst Du immer rechnen und dann hilft 2) wesentlich weiter. Es gibt einige Studien (sorry, keine Links da) die zeigen, dass ein sofortiger Response mit Verzögerung der realen Ergebnisse immer vorzuziehen ist, selbst wenn ein kompletter Response doppelt so schnell wäre.
Das war jetzt alles ein bischen durcheinander, aber ich hoffe es ist irgendwie hilfreich...
gepostet vor 17 Jahre, 9 Monate von DylanDog
Original von exception
Gerade in Bezug auf MyISAM spielen Table-Locks eine große Rolle. Sobald MySQL ein Update auf eine Tabelle ausführt oder ein INSERT in eine Tabelle mit nicht-fixer Spaltenbreite durchführt muss die gesamte Tabelle gesperrt werden.
Danke exception sehr nützliche erklärung..aber die Sperrung gilt nur für multiple/gleichzeitige INSERT oder habe ich das falsch verstanden? Ich verstehe dass ein user kann ein INSERT machen und ein andere ein SELECT (fast) ohne probleme:
From: www.mysql.org/doc/refman/5.1/en/internal-locking.html
"if a MyISAM table contains no free blocks in the middle, rows always are inserted at the end of the data file. In this case, you can freely mix concurrent INSERT and SELECT statements for a MyISAM table without locks. That is, you can insert rows into a MyISAM table at the same time other clients are reading from it. Holes can result from rows having been deleted from or updated in the middle of the table. If there are holes, concurrent inserts are disabled but are re-enabled automatically when all holes have been filled with new data.."
gepostet vor 17 Jahre, 9 Monate von exception
Original von DylanDog
Original von exception
Gerade in Bezug auf MyISAM spielen Table-Locks eine große Rolle. Sobald MySQL ein Update auf eine Tabelle ausführt oder ein INSERT in eine Tabelle mit nicht-fixer Spaltenbreite durchführt muss die gesamte Tabelle gesperrt werden.
Danke exception sehr nützliche erklärung..aber die Sperrung gilt nur für multiple/gleichzeitige INSERT oder habe ich das falsch verstanden? Ich verstehe dass ein user kann ein INSERT machen und ein andere ein SELECT (fast) ohne probleme:
From: www.mysql.org/doc/refman/5.1/en/internal-locking.html
"if a MyISAM table contains no free blocks in the middle, rows always are inserted at the end of the data file. In this case, you can freely mix concurrent INSERT and SELECT statements for a MyISAM table without locks. That is, you can insert rows into a MyISAM table at the same time other clients are reading from it. Holes can result from rows having been deleted from or updated in the middle of the table. If there are holes, concurrent inserts are disabled but are re-enabled automatically when all holes have been filled with new data.."
Stimmt, Locks entstehen nur, wenn Löcher aufgefüllt werden. Dennoch bringt fixe Zeilenlänge natürlich noch viele weitere Vorteile (vor allem kleinere Indizes, keine Fragmentierung der Daten).
gepostet vor 17 Jahre, 9 Monate von knalli
Okay, das sind gute Antworten. Vielen Dank.
Ich halte also fest: Aus Gründen der Performance besteht hier (bisher) die Meinung, das man jeweils eine Art Komposition mehrer Tabellen einer einer Entity macht. Die Einteilung daran festgehalten, was die Abfragen und Manipulationen ab effektivsten gestaltet.
Ich halte also fest: Aus Gründen der Performance besteht hier (bisher) die Meinung, das man jeweils eine Art Komposition mehrer Tabellen einer einer Entity macht. Die Einteilung daran festgehalten, was die Abfragen und Manipulationen ab effektivsten gestaltet.