Ab 100k Einträge kommen Fehler >gelöst<

sbr2d2

Registered User
Hallo zusammen,
ich weiß nicht genau wie ich das Problem beschreiben soll, aber ich versuch es mal.
Erstmal die Systemdaten, Ubuntu 18.04 (64-bit), Apache 2.4.29, PHP 7.2.24, MariaDB 10.1.47, phpMyAdmin 4.9.7.
Die Software arbeitet mit einer Datenbank mit dem Zusatz>> utf8mb4_general_ci. Keine Ahnung ob das wichtig ist.
Es gibt jetzt eine Tabelle wo man mittlerweile bei dem Eintrag 100000 angekommen ist. Die Software kann zwar immer weitere Einträge vornehmen, aktuell sind wir bei 100047, aber kann diese dann nicht mehr weiter verarbeiten. In anderen Tabellen sind wir schon weit über 100k Einträge, sprich bei 450k und mehr, da kommt das nicht vor. Wenn man über PHPmyadmin die Tabelle anschaut, bekommt man auch ab ca 99000 keine Ergebnisse mehr angezeigt. Lässt man sich die Tabelle von hinten an auflisten, sieht man aber die 100047 Einträge rückwärts fortlaufend. Aktuell weiß keiner wo das Problem sein könnte. Eine vergleichbare Tabelle arbeitet ohne fehler und ist bei 104000 Einträge.
Ich muss dazu sagen, ich bin weder der Programmierer der Software, noch der Typ der sich mit Datenbanken auskennt. Ich bin nur der Typ der die Betriebssysteme wartet und dafür sorgt das alles läuft. Ich suche nur nach Ideen die ich dann weiter reichen kann oder gegebenenfalls selber testen kann. Ich habe also volle Kontrolle über alle Systeme und kann benötigte Infos nachliefern. Die Logfiles liefern leider keine weiteren Erkenntnisse. Ich hoffe ihr habt ein paar Ideen was man noch probieren kann.
Gruß S.B.
 
Last edited:

d4f

Kaffee? Wo?
Am Rand: Wichtiger als die Codierung (utf8mb4_general_ci) ist der Engine-Typ (MyISAM, Inno, ....) der Tabelle und ob es Attribute/Indexe/Referenzen darauf gibt.

Zu PhpMyAdmin:
Phpmyadmin tut sich bspw generell schwer beim auflisten grosser Tabellen wenn diese keinen Index aufweisen oder er die Sortierungsfolge nicht korrekt interpretiert.

Zur Software:
Für mich klingt es nach einem Abfrage-/Designproblem der Software welches eine Limitierung der Maximalzeilen erwirkt, bspw durch sql_select_limit. Generell _sollte_ es nur sehr wenige Fälle geben wo man alle Zeilen einer Datenbank zurückgeben muss ohne über LIMIT Statements (sogenanntes Paging) zu fahren oder die Ergebnisse über WHERE auf eine Handvoll Ergebnisse zu filtern.
Um das Ergebnis zu analysieren würde ich empfehlen manuell einen entsprechenden SQL Befehl aus zu führen, bspw (Felder ersetzen)
Code:
SELECT COUNT(id) FROM <tabelle> LIMIT 999999
Das gesetzte LIMIT umgeht mögliche Standard-Limits auf Serverseite wie sql_select_limit für diesen Test.
 

sbr2d2

Registered User
Der Engine-Typ ist Inno-DB. Der aktuell verbliebene Programmierer findet keine Limitierung im Code. Was dagegen spricht wäre das ja weitere Einträge vorgenommen werden können. Also wäre jetzt meine Laienhafte Ansicht. Ich habe vielleicht noch einen anderen Ansatz. Die Daten aus der Tabelle werden gelesen und für eine andere Tabelle benötigt. Besteht die Möglichkeit, das man dort in einer bestimmten Spalte keine Werte über 99.999 eintragen kann? Wenn ja wie finde ich das heraus? Ich vermute nämlich so langsam, das ich in der falschen Tabelle den Fehler suche.
 

d4f

Kaffee? Wo?
Was dagegen spricht wäre das ja weitere Einträge vorgenommen werden können.
Das spricht allenfalls dafür dass die Datenbankengine keine Limitierung bei 100k, was auch sehr verwunderlich wäre. Ein Insert-Befehl zum Einfügen neuer Daten benötigt nicht dass die Applikation die existierenden Daten dafür durchliest.

er aktuell verbliebene Programmierer findet keine Limitierung im Code.
Welchen Rückgabewert gibt mein oben genannter Code denn?

Die Daten aus der Tabelle werden gelesen und für eine andere Tabelle benötigt
Ohne deine Datenbank und Tabellenstruktur zu können kommt mir das etwas seltsam vor. SQL ist der Inbegriff von relationaler Datenstruktur, will heissen alle Verbindungen zwischen einzelnen Tabellen und die zugehörige Logik (zB Table-Joins oder Views) wird in die SQL-Datenbank einprogrammiert, nicht in die nutzende Anwendung. Damit ist es eigentlich sehr sehr selten dass man alles auslesen muss. Als Erklärung was ich meine, um es an einem übersimplen Onlineshop-Beispiel zu veranschaulichen, hättest du die Struktur:
- Tabelle Kunde: KundenNr, Lieferadresse
- Tabelle Produkte: ProduktNr, ProduktName
- Tabelle Bestellungen: BestellNr, KundenNr, Status
- Tabelle BestellProdukte: BestellNr, ProduktNr
Um eine Bestellung mit Produkten und Lieferadresse an zu zeigen, geht man bei SQL-DBs nicht jeweils vollständig zuerst die Bestellungen auslesen, dann die Kunden, dann die BestellungsProdukte, dann die Produkte. Sondern in diesem Fall 2 Befehle (einer würde auch gehen, wäre aber etwas unstrukturiert)
-> Bestellungen
SELECT Kunde.Lieferadresse, Bestellungen.BestellNr FROM Kunde, Bestellungen WHERE Bestellungen.Status = "offen" AND Bestellungen.KundenNr = Kunde.KundenNr
-> Bestelldaten einer Bestellung
SELECT Produkte.ProduktName FROM BestellProdukte,Produkte WHERE BestellProdukte.BestellNr = "$aktuelle_bestellnr" AND BestellProdukte.ProduktNr = Produkte.ProduktNr


Um dir helfen zu können, bräuchte man deutlich mehr Daten über was und wie es verarbeitet wird, zb die verwendeten SQL Queries, Mysql Config, und ob die Daten wie im letzten Beitrag gefragt direkt abrufbar sind oder nicht.
 

sbr2d2

Registered User
Folgende Sachen wurden bei dem Befehl zurück gegeben>> SELECT COUNT(ID) FROM `marken` LIMIT 999999
Code:
Die aktuelle Markierung enthält keine eindeutige („unique“) Spalte. Gitter-Bearbeitungsfunktion, Kontrollkästchen, Bearbeiten, Kopieren und Löschen von Links sind nicht verfügbar.
COUNT(ID)     
59496
Es handelt sich um ein Browsergame und ehrlich gesagt, blicke ich da auch nicht wirklich durch. Aber so wie es aussieht läuft da alles über das Schema, auslesen, neu berechnen, speichern. Ich bin viel zu wenig Programmierer um das gezielt angehen zu können, bin mir aber ziemlich Sicher das es ein Datenbankproblem sein muss.
 

ThomasChr

Member
Klingt als willst du jemanden drüberschauen lassen der programmieren kann. Sonderlich kompliziert kann das eigentlich nicht sein!
 

sbr2d2

Registered User
Das wiederum nicht. Es gehört alles nicht mir und somit kann ich da nicht einfach jeden ran lassen. Mir ist aber daran gelegen den Fehler zu beseitigen. Ich habe jetzt Testweise den Eintrag 100000 auf Platz 1007 verschoben. Ab da konnte mit diesen Eintrag jetzt wieder gearbeitet werden. Ein Hotfix könnte jetzt so aussehen, das ein Skript die Tabelle ausliest, alles was über 99.999 steht ab Spalte 1000 an einen freien Platz wieder einsortiert. Die ersten 1000 Spalten sind für das Spiel reserviert. Das wäre ein Pflaster was für viele Jahre gehen würde. Die Tabelle aufräumen und alle Einträge in Reihenfolge neu anzulegen ist leider auch keine Option, da die Einträge über weitere 3-4 Tabellen verstrickt sind.

Sinnvoller wäre natürlich den Fehler zu finden. Tipps in Richtung das Spiel umzuschreiben sind aktuell nicht zielführend. Es sind einfach zu viele Dinge die gerichtet werden müssten. Bestes Beispiel ist, das leere Plätze nicht aufgefüllt werden. Also was es den Code vom Spiel angeht, geht es bestimmt besser, aber da bin ich wieder raus.
Aktuell gibt es also 2 Optionen.
1. Die Datenbank dahingehend dazu bewegen mit Einträgen über 100k klar zu kommen.
2. Skript welche die Einträge neu einsortiert jede Minute laufen lassen.

Wenn ihr mehr Ideen habt, gerne her damit :)
 

ThomasChr

Member
Ist der Programmcode denn wirklich so geheim dass den nicht mal jemand angucken kann der ein bisschen Ahnung hat? Der Fehler klingt wirklich nicht als wäre er außergewöhnlich kompliziert und deine Lösungsansätze scheinen mir entweder sehr verwirrend (a) oder absolut dreckig (b).

Wie schon weiter oben gesagt quasi jede normale Datenbank kommt leicht mit Millionen Einträgen klar. Da muss irgendwas sehr komisches im Programmcode gemacht werden. Aber ohne den zu sehen wirds niemand lösen können.

Und ich bin echt neugierig was da im Programmcode falsch läuft.
 

ThomasChr

Member
PS: Solltest du jemanden beauftragen der das für Geld macht so wird dieser wahrscheinlich auch eine NDA unterschreiben.
Alternativ schaltest du einfach einen Teamviewer und lässt denjenigen über deinen PC arbeiten während du zuschaust.
Ob das aber jeder will sei mal dahingestellt.
 

sbr2d2

Registered User
Das Problem wurde gelöst. @ThomasChr hat sich mal den Code angeschaut und folgendes gefunden.
Code:
if (isset($_POST['pro']) AND preg_match("#^[0-9]{1,5}$#", $_POST['pro'])){$pro = $_POST['pro'];}
        elseif (isset($_POST['pro2']) AND preg_match("#^[0-9]{1,5}$#", $_POST['pro2'])){$pro = $_POST['pro2'];}
Hier wird an 2 Stellen eine 5 stellige Abfrage gemacht, aber 6 stellig wird gebraucht.
So funktioniert es nun.
Code:
if (isset($_POST['pro']) AND preg_match("#^[0-9]{1,6}$#", $_POST['pro'])){$pro = $_POST['pro'];}
        elseif (isset($_POST['pro2']) AND preg_match("#^[0-9]{1,6}$#", $_POST['pro2'])){$pro = $_POST['pro2'];}
Vielen Dank an dieser Stelle an Thomas :)
 

GwenDragon

Registered User
Wenn nicht in einem Log eine sprechende Fehlermeldung zu der Begrenzung existiert, haben die Programmierer wohl gerade Party gefiert oder Azubis das eingebaut.
Lach, zeigt sich, dass niemand automatisiert Tests gefahren hat, sonst wäre euch das früher vor Release aufgefallen, dass was gegen die Grenze rennt.
Früher oder später fällt so Agile Prgramming eben jemand die Füße.
Warum überhaupt die Begrenzung auf 999.999, =fast 1 Million.
Was ist denn das für ein Programmdesign? So eine Obergrenze setzt man über eine PHP-Variable aus einer Konfiguration. So lässt sich eine Begrenzung besser steuern und man weiß wo man später zu setzen hat. Sowas als Festwert rein zu patchen ist kaum professionell und wird später auch wieder zu Problemen führen können. Ohne einen sinnvollen Kommentar warum sowas dort ist, nun ja, für Nachfolger viel Spaß.
Viel Erfolg beim Programmieren.
 

sbr2d2

Registered User
Da bin ich zum Glück raus. Habe aber von Thomas erfahren das noch zahlreiche solcher Limitierungen im Code stecken. Das ein oder andere wird sich dann zu gegebener Zeit bemerkbar machen. Viel schlimmer wird werden das der Code unter PHP 8 nicht mehr laufen wird. Entweder ist dann Ende oder es findet sich einer der das richten kann. Ich werde das programmieren vermutlich nicht mehr erlernen. Release war vor ca 8 Jahren.
 

danton

Debian User
Ohne den Rest des Codes zu kennen halte ich auf den ersten Blick eine Prüfung mit preg_match für eine schlechte Wahl Es sieht ja danach aus, als wenn per POST ein Integer-Wert übergeben wird. Da würde eine Prüfung mit Hilfe von intval() deutlich weniger rechenintensiv sein.
 

GwenDragon

Registered User
Ohne den Rest des Codes zu kennen halte ich auf den ersten Blick eine Prüfung mit preg_match für eine schlechte Wahl Es sieht ja danach aus, als wenn per POST ein Integer-Wert übergeben wird. Da würde eine Prüfung mit Hilfe von intval() deutlich weniger rechenintensiv sein.
Da bin ich sicher, dass die paar Microsekunden der ReEx-Engine mit einem festen Muster ohne jegliches Backtracking etc. nun wirklich nicht ins Gewicht fallen.
Ich tippe da eher auf andere grässliche Programmieraktionen, fehlende Indices, kein ausreichnder Cache für DB-Engine, die Zeitfresser sein könnten. Von richtigen Lücken udn nicht gefundenen gemeinen Bugs mal abgesehen. Wie schon @ThomasChr sagte Legacy PHP. Oder wie eineR auch gern sagt: "gewachsener Code" des Grauens. ;)
Aber ist doch eh nicht sein Bier sagte @sbr2d2 und auch nicht unsers.
 

sbr2d2

Registered User
Mir ist nur daran gelegen das es läuft weil mir das Spiel gefällt. Gewachsener Code bestimmt, haben ja auch schon ein paar Leute dran gewerkelt.
Ich werde bestimmt irgendwann wieder mit so was die Ecke kommen. Erstmal sind wir Thomas dankbar das es läuft und allen anderen die hier auch.
Gruß s.b.
 

danton

Debian User
@GwenDragon das bißchen Rechenzeit für den einen preg_match wird nicht groß ins Gewicht fallen. Aber vermutlich gibt es auch noch andere Dinge im Code, die ungünstig implementiert sind und wie heisst es so schon: "Viel Wenig gibt auch ein Viel" ;)
@sbr2d2 Jetzt wäre eine gute Gelegenheit, dran zu gehen und den ganze Code mal zu begutachten und auf den Prüfstand zu stellen und bezüglich PHP8 zu überarbeiten. Das wird einiges an Zeit in Anspruch nehmen, daher besser früher als später anfangen. Das Support-Ende von vielen Software-Produkten kommt immer so "plötzlich" ;):oops:
 

GwenDragon

Registered User
@danton
> Jetzt wäre eine gute Gelegenheit, dran zu gehen und den ganze Code mal zu begutachten und auf den Prüfstand zu stellen
Wenn die keine Testcases schreiben ist das sinnlos. Aber für Hobby-PHP-Code vielleicht auch nicht nötig.
 
Top