Linuchs: Konzept: PHP-include oder mySQL stored procedures?

Moin,

seit einigen Wochen räume ich meine Kalender-Programme auf.

Einerseits finde ich per Google längst vergessene wieder und kläre, ob ich die löschen kann, andererseits möchte ich den chronologisch gewachsenen Flickenteppich irgendwie strukturieren.

Der PHP-Code ist durch zahlreiche Datenbank-Zugriffe doch recht unübersichtlich und ich überlege, die DB-Zugriffe auszulagern. Dient dann auch der Umstellung auf MySQLi. Da sehe ich drei Möglichkeiten:

  • Ajax (wird schon verwendet für Vorschläge beim Tippen)
  • PHP-include (unüberschaubar viele Routinen vorhanden, mangels Verwendungsnachweis leider keine Übersicht, was noch gebraucht wird)
  • stored procedures, noch nicht vorhanden. Als ich 2002 mit mySQL anfing, gab es das noch nicht und meine vorhandenen Kenntnisse in Oracle verblassten mit den Jahren.

Heute habe ich die Suche bemüht mit „stored procedures“. Im Wiki stehen „stored functions“ (ist das dasselbe?) auf der to-do-Liste, im Forum ein seltenes Thema. In 2020 nur zweimal, scheint also in unserer Community keine Rolle zu spielen.

Was müsste ich beachten, wo sind die Grenzen und Fallstricke?

fragt Linuchs

  1. Hallo Linuchs,

    deine Frage ähnelt der nach dem Unterschied zwischen konkav und konkret.

    Ajax, PHP include und Stored Procedures sind Themen, die ziemlich disjunkt sind.

    Was Ajax ist, muss ich Dir nicht erklären. Aber mit Ajax lagerst Du aus deinem PHP Code keine DB Zugriffe aus.

    Mit PHP include kannst Du wiederholten Code in Dateien sammeln. Aber das allein ist nicht die Lösung. Ein include wird von PHP so behandelt, als stünde das includete PHP File an der Stelle, wo der inclue-Befehl steht. Es gibt keine Parameter. Es gibt keinen sinnvollen Return-Wert. Eine Sammlung von Codefragmenten, die mit include geholt werden, verschärft das Spaghetti.

    Wie fit bist Du mit selbstgemachten Klassen? Aus meiner Sicht sinnvoll sind sogenannte Repository-Klassen, die Zugriffe auf bestimmte Inhaltsdomänen bündeln. Das können die allgemeinen CRUD[1]-Zugriffe sein, aber eben auch Spezialzugriffe. Wichtig ist hier, die Zugriffe nicht zu spezifisch zu machen. Beim Bau eines Repository kann man sich viel Arbeit machen, die muss dann gut überlegt sein, oder man sammelt dort einfach alle Zugriffe für einen bestimmten Inhalt als Methoden. Ohne OOP muss man viele Funktionen bauen und mehr Parameter durchreichen.

    Stored Procedures oder Stored Functions sind Logikblöcke, die nicht im PHP, sondern in SQL Server ausgeführt werden. Du kannst komplexere Abfragen in Stored Procedures bündeln, aber tauschst damit nur einen Schwarm Zeugs im PHP gegen einen Schwarm Zeugs im SQL Server. Performancevorteile gewinnst Du damit nicht. Stored Procedures haben zwei Anwendungsfälle:

    (1) Security. Man kann Leuten Daten aus einer Table bereitstellen, ohne ihnen einen SELECT auf die Table oder einen View darauf zu GRANTen. Das ist für Dich uninteressant, weil Du ohnehin alle Zugriffe über eine technische User-ID machst.

    (2) Chattyness reduzieren. Wenn PHP und SQL auf unterschiedlichen Blech laufen, ggf. sogar noch mit einer latenzreichen Strecke dazwischen, ist Programmcode, der viele SQL Abfragen absetzen muss um ein bestimmtes Ergebnis zusammenzubauen, ineffizient. Je langsamer oder latenzreicher die Verbindung zwischen zwei Komponenten ist, desto eher gilt der Grundsatz: be chunky, not chatty. D.h. eine Query mit einem großen Ergebnis ist vielen kleinen Queries vorzuziehen. Wenn PHP und SQL auf dem gleichen Prozessor laufen, ist ggf. immer noch ein Unterschied da, aber er ist gering.

    Stored Procedures haben vor allem einen großen Nachteil: sie debuggen sich schlecht. In PHP kannst Du Debugger einsetzen, oder Dir den Wolf loggen. Bei Stored Procedures ist das schwieriger. Es ist auch mühseliger, in einer Stored Procedure mit dynamischem SQL zu arbeiten (ein Statement mit String-Operationen zusammenzusetzen. GEHEN tut es, es gibt PREPARE stmt FROM string als SQL Befehl.

    Stored Functions unterscheiden sich von Stored Procedures dadurch, dass sie einen Wert zurückgeben. Damit kannst Du sie in einem SQL Statement wie eine eingebaute Funktion verwenden. Die Stored Function kann selbst SQL durchführen, oder einfach nur Logik enthalten.

    Also - was Dir helfen sollte, ist eine Code-Reorganisation, so dass Du mit möglichst wenig unterschiedlichen SQL Zugriffen auskommst. Das ist erstmal viel Arbeit für die Bestandsaufnahme, vor allem bei Verwendung von dynamischem SQL. Und dann sieh zu, dass Du die Zugriffe sortierst und kapselst. Überleg Dir auch bei Monster-SQLs, ob es die Mühe Wert ist, das in SQL zu tun, oder ob man es auch mit einfacheren SQL Bausteinen im PHP zusammensetzen kann.

    Rolf

    --
    sumpsi - posui - obstruxi

    1. crud, engl. für Dreck oder Mist. CRUD - Akronym für Create Read Update Delete, also das Dreckszeug, das man immer wieder programmieren muss und wovon uns die ORM Frameworks erlösen wollen, um uns dafür crud auf anderem Level zu bescheren. ↩︎

    1. Hallo Rolf,

      danke für die sehr ausführliche Antwort.

      mit Ajax lagerst Du aus deinem PHP Code keine DB Zugriffe aus.

      Nein, aber ich kann per PHP die Programme nutzen, die auch per Ajax befragt werden. Die Programme, die 10 „schlanke“ Adressen / Orte / Mitglieder / Events / ... beim Tippen vorschlagen, können ja auch 100 „ausführliche“ Adressen / Orte ... für eine Liste liefern.

      Da diese Ajax-PHPs selbst die Datenbank (seit ein paar Tagen) mit MySQLi öffnen, müssen die „alten“ Programme nicht hektisch und fehlerriskant umgeschrieben werden.

      Wie fit bist Du mit selbstgemachten Klassen?

      Wenig Ahnung, vor vielen Jahren in einem Java-Semester kennengelernt. Bevor ich mich für PHP entschied.

      Überleg Dir auch bei Monster-SQLs, ob es die Mühe Wert ist, das in SQL zu tun, oder ob man es auch mit einfacheren SQL Bausteinen im PHP zusammensetzen kann.

      Habe immer noch kein Gefühl dafür, ob man für jeden SQL-Zugriff eine „Grundgebühr“ in Form von Zeit bezahlen muss. Ich vermute es.

      Gruß, Linuchs

  2. Fällt mir gerade ein:

    Die Ajax-Programme, die CSV-Strings liefern, könnte ich ja auch mit PHP aufrufen.

    1. Hallo Linuchs,

      nein, das solltest Du nicht tun. Ein per AJAX genutztes Script erwartet, dass es einen Request vom Browser bekommt.

      Korrekte Lösung, wie immer: Schichtenbildung.

      Presentation - Logic - Data Access.

      Presentation: Handling des HTTP Requests. Daten aus GET/POST holen, Ergebnis als CSV aufbereiten, CSV in die Response schreiben. Die CSV Aufbereitung an sich ist vermutlich etwas, das sich ebenfalls extrahieren und durch eine zentrale Logik implementieren lässt.

      Logic: Die PHP Logik um den eigentlichen Datenzugriff. Daten werden als Objekte oder assoziative Arrays geliefert.

      Data Access: Ist eh schon in den SQL Server ausgelagert, aber ggf. lohnt sich auch hier der Rückgriff auf ein Repository.

      Und dann kannst Du sowohl aus dem Ajax-Script und dem "anderen" Script einfach die Logic-Module des Ajax-Scripts nutzen.

      Rolf

      --
      sumpsi - posui - obstruxi
    2. Hallo,

      Die Ajax-Programme, die CSV-Strings liefern, könnte ich ja auch mit PHP aufrufen.

      könntest du vielleicht, aber das wäre ja "von hinten durch die Brust ins Knie".

      Der gängige AJAX-Mechanismus ist doch:

      • Client fordert eine HTTP-Ressource an, typischeweise mit Javascript ausgelöst
      • Server schmeißt PHP an, um den Request zu bedienen
      • PHP-Script liefert eine HTTP-Response
      • Client nimmt die Response entgegen und tut irgendwas damit

      Aus einem PHP-Script ein weiteres Script zu includieren, das für die AJAX-Kiste gemacht ist, wäre Unsinn. Dessen Antwort würde direkt an den Client gehen, der in diesem Mix nichts damit anfangen kann.
      Bei einem URL-Aufruf ginge die Antwort zwar an das anfragende PHP-Script, aber dann könntest du auch die Business-Logik des aufgerufenen Scripts direkt als Funktion aufrufen. Das wäre effizienter und leichter durchschaubar.

      Live long and pros healthy,
       Martin

      --
      Versuchungen sollte man nachgeben. Wer weiß, ob sie wiederkommen.
      1. Hallo Martin,

        Die Ajax-Programme, die CSV-Strings liefern, könnte ich ja auch mit PHP aufrufen.

        könntest du vielleicht, aber das wäre ja "von hinten durch die Brust ins Knie".

        Ich glaube, ich habe mich missverständlich ausgedrückt. Meine Ajax-Programme sind immer ein Paar. Das rufende JS-Programm und das antwortende PHP-Programm.

        Dem PHP-Programm ist es egal, wer ruft. Das checkt die $_GET-Parameter antwortet mit Daten oder Fehlermeldung.

        Beispiel

        Kleiner Performance-Nachteil: Das PHP-Programm öffnet die ohnehin offene Datenbank nochmal. Vorteil: Ich kann mySQLi nutzen, das Umschreiben der alten PHP-Zugriffe ist umständlich, zeitaufwändig und fehlerbehaftet.

        Die Umstellung von http zu https steckt mir noch warnend in den Knochen.

        Linuchs

        1. Hallo Linuchs,

          Vorteil: Ich kann mySQLi nutzen, das Umschreiben der alten PHP-Zugriffe ist umständlich, zeitaufwändig und fehlerbehaftet.

          Der Umstieg MYSQL -> MYSQLi ist eigentlich recht geradlinig. Aber ja, es ist lästig. Die technische Schuld "deprecated mysql" wirst Du durch Fake-Aufrufe der Ajax-Scripte jedenfalls nicht los.

          Eine Trennung der Ajax-Scripte in Web-Interface und Business Logic wäre trotzdem sinnvoll. Eine HTTP Schnittstelle zu simulieren ist wirklich nicht die beste Idee, und deine Ajax-Scripte setzen sicherlich Header, damit die JSON- oder CSV-Antwort korrekt zum Browser kommt. Das könnte dein nutzendes Script stören.

          Die Business Logik kannst Du ja in eine Funktion einkapseln, die ein MYSQLI-Objekt als Parameter bekommt und es in deinem anderen Script einfach bereitstellen. Das Ajax-Modul kann dann entscheiden, ob es das nutzt, oder ob es sich die Verbindung noch nach alt, via mysql, beschafft.

          Um keine Namenskonflikte zu bekommen, könntest Du noch erwägen, für die herausgelösten Business-Kerne namespaces zu verwenden - wenn Du das nicht ohnehin schon tust...

          Rolf

          --
          sumpsi - posui - obstruxi
        2. Hallo

          Meine Ajax-Programme sind immer ein Paar. Das rufende JS-Programm und das antwortende PHP-Programm.

          Soweit normal.

          Dem PHP-Programm ist es egal, wer ruft. Das checkt die $_GET-Parameter antwortet mit Daten oder Fehlermeldung.

          Ja. Das heißt also auch, ein PHP-Skript kann von mehreren Stellen aus aufgerufen werden. Solange das aufgerufene Skript (unter anderem) sicherstellt, dass der Aufruf von X aus erlaubt war, ist das kein Problem.

          Kleiner Performance-Nachteil: Das PHP-Programm öffnet die ohnehin offene Datenbank nochmal.

          Welche Datenbankverbindung ist denn noch offen, wenn du ein PHP-Skript per Ajax aufrufst?

          Tschö, Auge

          --
          Ein echtes Alchimistenlabor musste voll mit Glasgefäßen sein, die so aussahen, als wären sie beim öffentlichen Schluckaufwettbewerb der Glasbläsergilde entstanden.
          Hohle Köpfe von Terry Pratchett
          1. Hallo Auge,

            Welche Datenbankverbindung ist denn noch offen, wenn du ein PHP-Skript per Ajax aufrufst?

            Keine. Deswegen öffnet das Script sie ja.

            Aber wenn er es aus PHP heraus aufruft, gibt's schon eine MYSQLi-Verbindung, von der das Ajax-Script aber nichts weiß. Es öffnet selbst, und nun gibt es parallel eine MYSQLi und eine MYSQL Verbindung zur DB. Es ist zu hoffen, dass die beiden Treiber sich nicht gegenseitig beharken.

            Rolf

            --
            sumpsi - posui - obstruxi
            1. Hallo

              Welche Datenbankverbindung ist denn noch offen, wenn du ein PHP-Skript per Ajax aufrufst?

              Keine. Deswegen öffnet das Script sie ja.

              Aber wenn er es aus PHP heraus aufruft, gibt's schon eine MYSQLi-Verbindung, von der das Ajax-Script aber nichts weiß.

              Genau dieses Argument verstehe ich nicht. Wenn die Seite, aus der heraus später ein Ajax-Request erfolgen wird, an den Browser ausgeliefert wird, mag dort (noch) eine I-lose MySQL-Verbindung hergestellt werden. Die wird aber mit dem Ende der Abarbeitung dieses Skripts geschlossen und ist Geschichte. Erfolgt nun später der Ajax-Request, wird ein (anderes?) PHP-Skript aufgerufen, das seine eigene, nunmehr auf MySQLi basierende Datenbankverbindung herstellt. Wo kommt an dieser Stelle bitte eine andere, bereits offene Datenbankverbindung her?

              Es öffnet selbst, und nun gibt es parallel eine MYSQLi und eine MYSQL Verbindung zur DB. Es ist zu hoffen, dass die beiden Treiber sich nicht gegenseitig beharken.

              Ich habe sowas zwar noch nicht ausprobiert, aber aus der Logik heraus, dass in einem Skript durchaus mehrere Datenbankverbindungen mit einer Engine (MySQL oder MySQLi) hergestellt und unterhalten werden können, kann ich mir nicht vorstellen, dass das ein Problem ist.

              Jede Verbindung hat ihren Handler, der (zumindest bei MySQLi) in den Funktionsaufrufen sowieso angegeben werden muss, so dass das sauber auseinandergehalten werden kann. Bei Aufrufen mit der MySQL-Bibliothek ist die Angabe des Handlers zwar optional, aber nicht verboten, so dass das auch dort kein grundsätzliches Problem sein sollte. Verschiedene Handler, verschiedene Verbindungen. Ich vermute, dass man auch MySQLi und PDO für mehrere Datenbankverbindungen parallel in einem Skript verwenden könnte.

              Tschö, Auge

              --
              Ein echtes Alchimistenlabor musste voll mit Glasgefäßen sein, die so aussahen, als wären sie beim öffentlichen Schluckaufwettbewerb der Glasbläsergilde entstanden.
              Hohle Köpfe von Terry Pratchett
              1. Hallo Auge,

                ich habe Linuchs anders verstanden. Er hat ein PHP Script xyz.php, das bestimmte Daten benötigt. Dieses Script ist bereits auf MYSQLi umgestellt.

                Und er hat ein PHP Script ajax1.php, das für Ajax-Zugriffe gemacht ist und noch den alten MYSQL Treiber verwendet. Sein Output sind gerade die Daten, die xyz.php braucht. Und hoffentlich auch in genau dieser Form braucht.

                Statt nun den Datenbeschaffungscode aus ajax1 zu kopieren, in xyz.php einzufügen und dort auf MYSQLi umzustellen, ruft Linuchs aus xyz.php heraus das ajax1.php auf und lässt es im Glauben, es sei vom Browser aus aufgerufen worden. ajax1.php weiß nichts vom übrigen Kontext, es weiß nichts von der offenen MYSQLi-Verbindung von xyz.php, es macht einfach seinen Stiefel und produziert seinen gewohnten Output. Der wird von xyz.php abgefangen und weiterverwendet.

                Sofern ajax1.php halbwegs ordentlich programmiert ist, kann das gelingen. Problem ist nur: Das ajax1.php ist nicht dafür gebaut worden, von einem anderen PHP Script eingebunden zu werden. Wenn sich also - wie für ein Hauptprogramm üblich - ganz wie zu Hause fühlt und überall schmutziges Geschirr und leere Chipstüten rumliegen lässt, könnte es sein, dass xyz.php irgendwann über den Müll stolpert.

                Deswegen trommele ich ja dafür, ajax1.php zu entkernen und den Logikkern wiederverwendbar zu machen.

                Rolf

                --
                sumpsi - posui - obstruxi
                1. Hallo Rolf,

                  Deswegen trommele ich ja dafür, ajax1.php zu entkernen und den Logikkern wiederverwendbar zu machen.

                  Auch eine Idee. Dann ist der Kern ein include und kann sowohl im „normalen” PHP-Programm ohne (zusätzliches) Öffnen der Datenbank und im PHP-Ajax-Antwort-Programm mit Öffnen der DB verwendet werden.

                  Linuchs

              2. Hallo Auge,

                Erfolgt nun später der Ajax-Request, wird ein (anderes?) PHP-Skript aufgerufen, das seine eigene, nunmehr auf MySQLi basierende Datenbankverbindung herstellt. Wo kommt an dieser Stelle bitte eine andere, bereits offene Datenbankverbindung her?

                Richtig, in diesem Falle nicht. Wir betrachten doch die Alternative, dass PHP-Programm A vor Auslieferung an den Browser von PHP-Programm B Daten anfordert. Einfach deshalb, um den gleichartigen Programmcode in Programm A zu sparen samt Pflege und Fehler-Anfälligkeit.

                Die Idee finde ich nicht so ungewöhnlich, habe vor Jahren anderen Webmastern eine Schnittstelle zur Verfügung gestellt, die genau das macht: Rohdaten liefern. Zuvor konnte man Kalender nur als iframe einbinden und hatte keine Möglichkeit, sie auf das eigene Layout zu trimmen.

                Keiner hat die Möglichkeit genutzt. Ich komme aus der Groß-EDV mit internationalem Datenaustausch, Fachleute trauen einem Einzelkämpfer solche Kenntnisse womöglich nicht zu (ist ja auch berechtigt, bei Großprojekten braucht man ein Team), Gelegenheits-Webmaster sehen darin eine Lösung, zu der ihnen das Problem fehlt.

                Deshalb ist es mir mittlerweile auch recht schnuppe, welches Datenformat ich intern verwende. Es soll schnell zu erzeugen und zu übermitteln sein. Bei CSV sind immerhin ein paar Leute interessiert, die mit Kalkulationsprogrammen arbeiten.

                Da sämtliche Daten aus der Datenbank per Platzhalter-Datei aufbereitet an den Browser geschickt werden, kann ich morgen mit einem zusätzlichen Template ein beliebiges Datenformat erzeugen. Ich muss es nur verstehen und mich einarbeiten.

                Eine Ausnahme, die nicht per Template zu lösen ist, kenne ich: PDF-Dateien. Da habe ich mich inzwischen aber auch eingearbeitet.

                Das Ganze ist inzwischen zum Hobby und zur Beschäftigungstherapie für die grauen Zellen geworden. Wegen Corona kommen kaum noch Termine rein, ich wundere mich über mich selbst, warum ich so an diesem Projekt hänge.

                Ich möchte mich mehr der Musik und der Chorarbeit widmen und sitze wieder vorm PC, um Arrangements zu schreiben. Das ist im Moment genauso nutzlos.

    3. Die Ajax-Programme, die CSV-Strings liefern, könnte ich ja auch mit PHP aufrufen.

      Also, wenn Du schon aufräumst, dann tust Du Dir selbst sicherlich einen echten Gefallen, wenn Du dabei auch gleich die Antworten von CSV auf auf JSON umstellst…

      1. Hallo RaketenObjektNotierer,

        grins, dieses Fass wollte ich nicht auch noch öffnen. Und ich glaube auch nicht, dass das zu einer fruchtbaren Diskussion führt. Ich befürchte einen Buchstabendreher an Stelle 2 und 3.

        Es ist aber auch die Frage, für was die CSV Strings gebraucht werden. Vielleicht soll das ja ein CSV Export sein.

        Rolf

        --
        sumpsi - posui - obstruxi
        1. (JSON statt CSV)

          grins, dieses Fass wollte ich nicht auch noch öffnen.

          Wie das mit dem Wollen, Sollen und Müssen halt so ist…

          Hab vergessen darauf hinzuweisen, dass (Kontext anderer Fragen bzw. Probleme) dann („von der Taufe bis zu Rente“) auch die Nutzung von UTF-8 konsequent durchgesetzt werden sollte.

          Dies alles natürlich zusammen mit Deinem Hinweis auf das nicht weniger konsequente Aufräumen und Kapseln in Objekten. Besser man macht es gleich richtig - also vorher einen Plan. („Im Anfang stand das Wort.“)

          1. Hallo RaketenObjektNotierer,

            „Im Anfang stand das Wort.“

            Und das Wort wuchs und gedieh, und es füllte Bücher und Pläne, und siehe, als das Werk begann, war das Wort veraltet und der Kunde weg.

            Wenn man Raketen baut, muss man alles vorweg planen. Wenn die Rakete oben ist, gibt's keine Patches für den Antrieb.

            Als man in den 60ern Software gebaut hat, hat man Raketenmethodik verwendet und es entstanden monströse Dinge wie Vorgehensmodelle, Phasenkonzepte und riesige Wasserfälle.

            Wenn man heute Software baut (außer für Steuerungszwecke, z.B. von Raketen), fängt man klein an und baut dann aus.

            Und egal ob 60-er oder 10-er Technik, nach ein paar Jahren ist der beste Plan Spaghetti. Und dann muss man den Mut und die Kraft haben, Dinge neu zu denken, neu zu bauen, und einen neuen Plan zu machen. Auch wenn der unmittelbare Nutzen NULL ist. Leider bezahlt das kein Kunde.

            Rolf

            --
            sumpsi - posui - obstruxi
            1. Hallo Rolf B,

              Und egal ob 60-er oder 10-er Technik, nach ein paar Jahren ist der beste Plan Spaghetti. Und dann muss man den Mut und die Kraft haben, Dinge neu zu denken, neu zu bauen, und einen neuen Plan zu machen. Auch wenn der unmittelbare Nutzen NULL ist. Leider bezahlt das kein Kunde.

              Der unmittelbare Nutzen ist niemals NULL. Zumindest der eigene Wissens-, Erkenntnis- und Kompetenzzuwachs ist vorhanden und sollte nicht zu gering geschätzt werden.

              Bis demnächst
              Matthias

              --
              Du kannst das Projekt SELFHTML unterstützen,
              indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
              1. Hallo Matthias,

                entschuldige. Ich meinte den Nutzen für den Kunden. Der bekommt nach einer Refaktorierung die gleichen Funktionen und vielleicht ein paar frische Bugs. Und während der Refaktorierung müssen Änderungswünsche zurückstehen.

                Der Nutzen des Refactorings ist nur indirekt fassbar. Weiterentwicklungen können preiswerter oder überhaupt erst möglich werden. Aber das sieht ein Kunde nicht.

                Natürlich ist es nicht immer so, dass man die Welt anhält während ein Refactoring läuft. Man macht es schleichend, nach dem Pfadfinder-Prinzip[1], aber schonmal muss man doch die Axt ansetzen. Dafür ist Linuchs' Idee, seine Ajax-Zugriffe wiederzuverwenden, nicht schlecht, aber der Weg taugt meiner Meinung nach nichts. Er sollte (1) die Ajax-Module entkernen, (2) den Kern auf MYSQLi umstellen und (3) das dann wiederverwenden. Alles andere zahlt die technische Schuld nicht ab, sondern verlagert sie nur.

                Rolf

                --
                sumpsi - posui - obstruxi

                1. Versucht, die Welt ein bisschen besser zurückzulassen, als ihr sie vorgefunden habt.
                  -- Robert Baden-Powell, 1941 ↩︎

                1. den Kern auf MYSQLi umstellen

                  Nicht besser auf PDO? Ich sehe nämlich zunehmend auch sqlite-Datenbanken.

                  1. Hallo RaketenObjektNotierer,

                    diese Umstellung ist größer als mysql -> mysqli.

                    SQLite, klar, das ist für Webs mit geringem Update-Aufkommen machbar, die auf einem einzigen Server laufen. Jaaa, ich weiß, man kann die DB auch auf einem Fileshare ablegen. Aber ist das für eine DB wirklich sinnvoll? Sollte man, wenn man für einen Datenbestand schon zwei Webserver fährt, nicht auch die DB auf ordentliche Füße stellen, damit man sie im Zweifelsfall auf einen dritten Server skalieren kann? Ich rede nicht von "kann man das hinzubekommen?". Ist es sicherlich. Sondern ich rede von "ist das eine problemangemessene Lösung?". Aber vielleicht bin ich ja auch zu sehr vom großen Unternehmen geprägt.

                    Und es ist definitiv out of scope für Linuchs, würde ich sagen.

                    Aber nebenbei habe ich einen sehr interessanten Link im SQLite Handbuch gefunden:

                    The Problem With Threads

                    Den abrupten Abstieg in die theoretische Informatik zu Beginn kann man versuchen zu verstehen, oder ignorieren 😉

                    Rolf

                    --
                    sumpsi - posui - obstruxi
      2. Hallo Raketen*,

        Also, wenn Du schon aufräumst, dann tust Du Dir selbst sicherlich einen echten Gefallen, wenn Du dabei auch gleich die Antworten von CSV auf auf JSON umstellst…

        Ich mag Zwetschenkuchen, du empfielst Sahnetorte. Solange keine Begründung kommt, ist das reine Geschmackssache.

        Habe mir das Datenformat JSON angeschaut, Die Daten selbst sind ja nur ein Bruchteil, immer wieder müssen die Keys angegeben werden. Ich nenne das Redundanz, also Schaumschlägerei bzw. Sahnetorte.

        Linuchs

        1. Hallo,

          Also, wenn Du schon aufräumst, dann tust Du Dir selbst sicherlich einen echten Gefallen, wenn Du dabei auch gleich die Antworten von CSV auf auf JSON umstellst…

          Ich mag Zwetschenkuchen, du empfielst Sahnetorte. Solange keine Begründung kommt, ist das reine Geschmackssache.

          ein Argument pro JSON könnte sein, dass zahlreiche Scriptsprachen schon fertige Funktionen zur Verarbeitung von JSON haben.

          Ein weiteres könnte sein, dass JSON sehr weitgehend standardisiert ist und daher als universelles Datenaustauschformat taugt, während die Spezifikation von CSV sehr schwammig ist.

          Habe mir das Datenformat JSON angeschaut, Die Daten selbst sind ja nur ein Bruchteil, immer wieder müssen die Keys angegeben werden.

          Bei Objekten ja, bei Arrays (was der CSV-Lösung ähnlich wäre) nicht.

          Ich nenne das Redundanz, also Schaumschlägerei bzw. Sahnetorte.

          Sagen wir's so: Wenn sowohl die Software, die CSV erzeugt, als auch die Software, die das empfängt und verarbeitet, von dir sind (wenn du also alle Aspekte selbst in der Hand hast), spricht nichts gegen CSV. Als universelles Austauschformat taugt es aber wegen der vielen Varianten und der ungenauen Spezifikation nicht.

          Live long and pros healthy,
           Martin

          --
          Versuchungen sollte man nachgeben. Wer weiß, ob sie wiederkommen.
          1. ein Argument pro JSON könnte sein, dass zahlreiche Scriptsprachen schon fertige Funktionen zur Verarbeitung von JSON haben.

            Neben dem "Komfort" könnte ein weiteres Argument sein, dass die Implementation von JSON weitgehend hochoptimiert ist. Ich habs beruflich oft mit "fetten" JSON-Paketen zu tun. Die Performance ist auf Server wie auch Clientseite (z.B. Firefox und vor allem Chrome) erstaunlich.

            Habs nicht gemessen, würde aber einiges darauf wetten, dass ein selbstgefriemeltes "CSV-Split" dagegen keine Chance hat.

            1. Irgendwie fand ich den Gedanken „wenn Deine Seite nicht jedesmal beim Aufruf das New Yorker Telefonbuch mitliefert“ ja interessant, also habe ich was gebastelt…

              Zunächst findet man das New Yorker Telefonbuch als CSV recht schnell im Netz. War mir mit über 500K Datensätzen und 180 Megabyte aber etwas drüber für einen Test. Also das Teil auf (produktiv für einen Ajax-Call immer noch absurd viel) 2000 Einträge reduziert.

              Um daraus nun ein JSON zum Vergleich zu bekommen, habe ich https://csvjson.com/ zur Hilfe genommen.

              Im Ergebnis kommt dabei natürlich, wie von Linuchs befürchtet, ein fürchterlicher Overhead heraus. Das CSV ist ca. 1,8 Megabyte groß und das JSON ca. 6,5 Megabyte.

              Liefert der Webserver die beiden Kandidaten aber komprimiert (in meinem Test gzip) aus, entschärft sich die Situation deutlich: CSV ca. 130 Kilobyte, JSON ca. 190 Kilobyte. Wie schon erwähnt, mit absurden Datenmengen, aber sonst lässt sich das halt nicht vernünftig messen.

              Jetzt zur Verarbeitung. Getestet im Firefox und Chrome, die Ergebnisse sind ähnlich. Wenn ich das CSV als String einfach nur auf Linefeeds und in einer Schleife dann auf Komma splitte, um einen Gesamtarray zu bilden, den ich nachfolgend dann auf „length“ in die Console printe, dann liegt CSV im Vergleich zu „JSON.parse(data).length“ ca 10ms vorne. Chrome ist erwartungsgemäß insgesamt schneller. Im Firefox komme ich hier beim CSV auf ca. 15ms, bei JSON auf ca 25ms. Rein von der Performance liegt CSV also bislang vorne.

              Nur ist das simple Split auf Linefeeds und Komma bei CSV ja geradezu naiv und fehleranfällig. Also braucht man einen Parser. Im Gegensatz zu JSON gibt es den aber nicht nativ implementiert. Laut eigener Aussage ist hier Papa Parse „the fastest in-browser CSV parser for JavaScript“. Macht wirklich einen ausgereiften Eindruck und ist beeindruckend schnell.

              Dennoch wendet sich hier das Blatt und das native „JSON.parse“ ist ca. 30% schneller. Trotz des ca. 3-fachen, zu verarbeitenden Datenvolumens.

              Damit kann man hier mit „klawischniggs Fazit“ schließen: „dann fällt vermutlich nicht nur mir kein Grund ein, warum man kein JSON-Format verwenden sollte...“

              JSON ist schneller, robuster und handlicher.

              1. Moin Mitleser,

                danke für die Mühe.

                Jetzt zur Verarbeitung. Getestet im Firefox und Chrome, die Ergebnisse sind ähnlich. Wenn ich das CSV als String einfach nur auf Linefeeds und in einer Schleife dann auf Komma splitte, um einen Gesamtarray zu bilden, den ich nachfolgend dann auf „length“ in die Console printe, dann liegt CSV im Vergleich zu „JSON.parse(data).length“ ca 10ms vorne. Chrome ist erwartungsgemäß insgesamt schneller. Im Firefox komme ich hier beim CSV auf ca. 15ms, bei JSON auf ca 25ms. Rein von der Performance liegt CSV also bislang vorne.

                Hast du den Benchmark noch irgendwo herumfliegen und würdest ihn mit uns teilen? Mich interessiert, ob sich Response.prototype.json anders verhält als JSON.parse. Ich würde erwarten Response.prototype.js schneller ist, weil es mit dem Parsen nicht warten muss, bis der Download vollständig abgeschlossen ist. Die Funkion kann bereits mit dem Parsen beginnen noch während der Download läuft.

                VG

                1. Hast du den Benchmark noch irgendwo herumfliegen und würdest ihn mit uns teilen?

                  Klar:

                  var request = new XMLHttpRequest();
                  request.open('GET', '/ny.json.txt', true);
                  request.onload = function() {
                  	console.time("PROCESS");
                  	var fullData = JSON.parse(request.responseText);
                  	console.log(fullData.length);
                  	console.timeEnd("PROCESS");
                  };
                  request.send();
                  

                  Ich hätte das komplette Testsetup gerne veröffentlicht, aber das mir alleine schon wegen der verwendeten Telefonbuchdaten zu „heiß“.

                  Mich interessiert, ob sich Response.prototype.json anders verhält als JSON.parse. Ich würde erwarten Response.prototype.js schneller ist, weil es mit dem Parsen nicht warten muss, bis der Download vollständig abgeschlossen ist. Die Funkion kann bereits mit dem Parsen beginnen noch während der Download läuft.

                  Kann ich mir durchaus vorstellen. Hatte mich bewusst gegen „fetch“ entschieden, um den Vergleich möglichst „auf den Punkt“ zu bringen.

        2. Hallo Linuchs,

          Ich mag Zwetsch(g)enkuchen, du empfie(h)lst Sahnetorte.

          Ich mag vor allem Zwetschgenkuchen mit Sahne drauf!

          Ja, JSON ist geschwätziger, weil es Objekte als Key-Value Paare speichert. Bei einer einzigen Datenzeile ist das genau wurscht.

          Bei 1000 Datenzeilen und geschätzten 400 Bytes für Propertynamen sind das 400K Mehrdatenvolumen; vermutlich mehr Daten für Overhead als für Inhalt, also schon sehr signifikant. Das kannst Du durch GZIP Kompression der dynamisch erzeugten Inhalte kompensieren (beim IIS muss ich das explizit einschalten); da die Propertynamen ständig gleich sind, komprimieren sie gut. Dafür dauert das GZIPpen seine Zeit und mümmelt CPU Kerne.

          Deine Abwägung, und Du hast sie getroffen.

          Ich hätte eine Challenge für Dich. Du könntest das Datenvolumen noch mehr straffen, wenn Du ein binäres Format statt CSV wählst.

          1. bestimme die String-Repräsentation jedes Feldes
          2. setze vor den Feldinhalt ein Zeichen, dessen Zeichencode der Feldlänge entspricht. Bei UTF-8 Codierung gehen Feldlängen bis 127 als ein Byte über die Leitung.
          3. setze Feldlängen und Feldinhalte zusammen und setze davor noch ein Zeichen, dessen Zeichencode der Anzahl der Felder entspricht.

          So schreibst Du Satz für Satz 'raus. Auf String-Delimiter und Escaping von Sonderzeichen brauchst du nicht zu achten, wegen der Feldlängenangaben. Nach dem letzten Satz schreibst Du noch ein Nullbyte - ein Satz ohne Felder - als Terminator.

          Rolf

          --
          sumpsi - posui - obstruxi
        3. Habe mir das Datenformat JSON angeschaut, Die Daten selbst sind ja nur ein Bruchteil, immer wieder müssen die Keys angegeben werden.

          <?php
          $ar[] = ['Eins','Zwei','Drei'];
          $ar[] = ['Vier','Fünf','Sechs'];
          $ar[] = ['Sieben','Acht','Neun'];
          echo json_encode( $ar) ;
          
          [["Eins","Zwei","Drei"],["Vier","F\u00fcnf","Sechs"],["Sieben","Acht","Neun"]]
          

          Das ist „keyless“.

          CSV kann auch keine Spaltennamen. Und wenn Du in CSV die erste Zeile dafür missbrauchen kannst, dann gänge das auch in JSON...

          1. Hallo RaketenObjektNotierer,

            Das ist „keyless“.

            Das spricht sich ähnlich, aber du meinst bestimmt Kahless, oder?

            Ich hatte schon die Idee einer Transponierung auf der Pfanne, um die Spaltennamen zu behalten.

            $data = [
               "name" => [ "Schmitz", "Schweiß", "Picard" ],
               "vorname" => ["Jupp", "Axel", "Jean-Luc" ],
               "beruf" => "Köbes", "Avon-Berater", "Kapitän" ]
            ];
            
            echo json_encode($data, JSON_UNESCAPED_UNICODE) ;
            

            ergibt

            {"name":["Schmitz","Schweiß","Picard"],"vorname":["Jupp","Axel","Jean-Luc"],"beruf":["Köbes","Avon-Berater","Kapitän"]}

            Das Herstellen der transponierten Darstellung kostet nur ordentlich Laufzeit, weil da bei n Spalten n Arrays gepusht werden müssen. Eine fertige Array-Funktion, die das ggf. effizienter tun könnte, habe ich jedenfalls nicht entdeckt.

            Rolf

            --
            sumpsi - posui - obstruxi
        4. Hi there,

          Habe mir das Datenformat JSON angeschaut, Die Daten selbst sind ja nur ein Bruchteil, immer wieder müssen die Keys angegeben werden. Ich nenne das Redundanz, also Schaumschlägerei bzw. Sahnetorte.

          Und ich nenne Dich "Eroberer des Nutzlosen".

          Wenn Du die Datenmenge nicht nach Bytes bezahlst (wovon ich ausgehe) oder die Daten einzeln auf Diskette auslieferst (wovon ich noch viel mehr ausgehe) dann kann es Dir eigentlich ziemlich bis extrem wurscht sein, wie groß da irgendein Overhead ist oder nicht - auch und besonders, weil diese Daten in dem allermeisten Fällen (ja, ok, Dein Diskettentransport nicht;) komprimiert ausgeliefert werden.

          Mit anderen Worten, wenn Deine Seite nicht jedesmal beim Aufruf das New Yorker Telefonbuch mitliefert, dann fällt vermutlich nicht nur mir kein Grund ein, warum man kein JSON-Format verwenden sollte...

        5. Habe mir das Datenformat JSON angeschaut, Die Daten selbst sind ja nur ein Bruchteil, immer wieder müssen die Keys angegeben werden. Ich nenne das Redundanz, also Schaumschlägerei bzw. Sahnetorte.

          „Linuchs“, the Optimizer.