Tom: MySQL: arbeiten mit Limit

Hello,

ich trage gerade meine gesammelten Werke zum Thema LIMIT zusammen.

Zum einfachen Vorblättern muss man ja immer nur $offset+=$limit rechnen und zum Zurückblättern $offset-=$limit.

Wenn $offset < 0 dann $offset = 0.

Was aber macht man am hinteren Ende, damit man nicht über's Ziel hinausschießt. Es gibt ja den bekannten Trick, einfach einen Satz mehr abzufragen (also $limit + 1) und wenn der nicht mehr da ist, kein "Vorwärts" mehr anzubieten. Aber das ist mir mal wieder zu unsicher in dynamischen Datenbeständen. Es könnten ja seit dem letzten am hinteren Anschlag Angekommen sein Datensätze hinzugekommen sein (durch andere User).

Welches Statement würdet Ihr benutzen um nun vorab nur die Geamtanzahl der dem Filterkriterium (wahrscheilich "where ...") entsprechenden Datensätze herauszufinden. Felder benötigt man ja eigentlich nicht.

Select count(ID)from table where...;

Ist das das performanteste, was man sich denken könnte?

Eine kleine Unsicherheit gibt's dann ja trotzdem noch, weil zwischen dem Zähl-Select und dem gefüllten mit limit auch wieder Zeit vergeht. Aber damit könnte man leben, da das ja erst relevant wird, wenn $offset > $count werden würde.

Grüße

Tom

  1. hi,

    Welches Statement würdet Ihr benutzen um nun vorab nur die Geamtanzahl der dem Filterkriterium (wahrscheilich "where ...") entsprechenden Datensätze herauszufinden.

    Select count(ID)from table where...;
    Ist das das performanteste, was man sich denken könnte?

    bei nummerisch fortlaufenden IDs würde ich eher zu SELECT MAX(id) tendieren.
    wenn du keine solche nummerische, fortlaufende ID hast, dann wohl ebenfalls COUNT().

    gruss,
    wahsaga

    1. Hello,

      bei nummerisch fortlaufenden IDs würde ich eher zu SELECT MAX(id) tendieren.
      wenn du keine solche nummerische, fortlaufende ID hast, dann wohl ebenfalls COUNT().

      Das ist vielleicht ein Tipp *tztz* Stammt der wirklich von DIR?

      Da können doch inzwischen tausende von Sätzen fehlen aus dem Nummernkreis, selbst wenn die mal fortlaufend angelegt wurden.

      Mir schmeckt das gar nicht mit dem extra-Query. Wird aber wohl nicht anders gehen, oder?

      Grüße

      Tom

      1. hi,

        bei nummerisch fortlaufenden IDs würde ich eher zu SELECT MAX(id) tendieren.

        Das ist vielleicht ein Tipp *tztz* Stammt der wirklich von DIR?

        Da können doch inzwischen tausende von Sätzen fehlen aus dem Nummernkreis, selbst wenn die mal fortlaufend angelegt wurden.

        ja sorry, ich mach das so in meinem blog - da wird nicht zensiert, also entstehen auch keine lücken :-)

        gruss,
        wahsaga

        1. Hello,

          ja sorry, ich mach das so in meinem blog - da wird nicht zensiert, also entstehen auch keine lücken :-)

          Ja, nett ausgedrückt. Aber ich betreibe keine Zensur. Das machen die User selber

          PAGE
            ITEM
            ITEM
            ITEM

          Die legen sich Seiten an und setzen in die Seiten Anzeigeelemente. Von Zeit zu Zeit werden die verändert oder eben gelöscht und neue kommen hinzu. Mich interessieren nur die veränderten, um notfalls dann eben doch mal ne Sperre setzen zu können, wenn's rechtswidirg wird.

          Wie das mit der Einhaltung der oberen Grenze funktioniert habe ich dank Eurer Anregungen nun hinbekommen. Aber trotzdem würde mich interessieren, wovon die Performance in einem "Zählquery" abhängen kann.

          Grüße

          Tom

  2. Hallo!

    Was aber macht man am hinteren Ende, damit man nicht über's Ziel hinausschießt. [...]

    -> 10 Datensätze / Seite -> ansicht=10

    1. Wieviel Datensätze sind ingesamt betroffen? (z.B. 59 Stück) -> anzahl

    2. Holen der Datensätze mit LIMIT.

    // Annahme: seite=6
    3.
       if(seite>1)
          {
             "zurück"
          }

    // 59-(10*(6-1))=9 -> also kein weiter
       if((anzahl-(ansicht*(seite-1)))>(ansicht))
          {
             "weiter"
          }

    Aber das ist mir mal wieder zu unsicher in dynamischen Datenbeständen. Es könnten ja seit dem letzten am hinteren Anschlag Angekommen sein Datensätze hinzugekommen sein (durch andere User).

    Zu vernachlässigen.

    Eine kleine Unsicherheit gibt's dann ja trotzdem noch, weil zwischen dem Zähl-Select und dem gefüllten mit limit auch wieder Zeit vergeht. Aber damit könnte man leben, da das ja erst relevant wird, wenn $offset > $count werden würde.

    Das kannst kaum messen!

    MfG, André Laugks

    --
    L-Andre @ gmx.de
    1. Hello,

      1. Wieviel Datensätze sind ingesamt betroffen? (z.B. 59 Stück) -> anzahl

      Genau das ist das Problem. Wieviel Datensätze sind es zum Zeitpunkt der Abfrage?

      Aber das ist mir mal wieder zu unsicher in dynamischen Datenbeständen. Es könnten ja seit dem letzten am hinteren Anschlag Angekommen sein Datensätze hinzugekommen sein (durch andere User).

      Zu vernachlässigen.

      Eben nicht. Es hndelt sich um eine Bewegungsdatentabelle und keine Stammdatentabelle. Da ändert sich sekündlich was. Ich kann dem Operator also nicht einfach seinen "nächste Seite" Button wegnehmen. Ich muss nur verhindern, dass er über die obere Query-Border hinauszählt.

      Die untere liegt ja glücklichrweise mit 0 fest.

      Eine kleine Unsicherheit gibt's dann ja trotzdem noch, weil zwischen dem Zähl-Select und dem gefüllten mit limit auch wieder Zeit vergeht. Aber damit könnte man leben, da das ja erst relevant wird, wenn $offset > $count werden würde.

      Das kannst kaum messen!

      Doch, in Mikrosekunden lässt sich das messen.

      Grüße

      Tom

      1. Hallo Tom,

        Aber das ist mir mal wieder zu unsicher in dynamischen Datenbeständen. Es könnten ja seit dem letzten am hinteren Anschlag Angekommen sein Datensätze hinzugekommen sein (durch andere User).

        Zu vernachlässigen.

        Eben nicht. Es hndelt sich um eine Bewegungsdatentabelle und keine Stammdatentabelle. Da ändert sich sekündlich was. Ich kann dem Operator also nicht einfach seinen "nächste Seite" Button wegnehmen. Ich muss nur verhindern, dass er über die obere Query-Border hinauszählt.

        Biete diesen Button doch einfach immer an, und prüfe erst, wenn der Button geklickt wurde.

        Bye,
        Peter

        1. Hello Peter,

          Biete diesen Button doch einfach immer an, und prüfe erst, wenn der Button geklickt wurde.

          [snip]
            elseif ($_POST["btn"]["next"])
            {
              $_SESSION["offset"]+= $limit;
            }
            elseif ($_POST["btn"]["prev"])
            {
              $_SESSION["offset"]-=$limit;
              if($_SESSION["offset"] < 0)
              {
                $_SESSION["offset"] = 0;
              }
            }

          $offset = $_SESSION["offset"];

          ## Query

          [snap]

          Das tue ich ja (siehe Scriptauszug).

          Nun stell Dir vor, da war im Moment nur noch ein Satz anzuzeigen, $offset ist aber schon um $limit erhöht, also wesentlich weiter...

          Man könnte natürlich, wenn $num = mysql_num_rows($res) nach dem Statement bekannt ist die Differenz bilden:

          $diff=$num-$limit;
          $_SESSION["offset"]+=$diff;

          Davon weiß ich aber immer noch nicht, wieviele Sätze es insgesamt sind im Filterbereich, sodass man anzeigen kann

          Treffer 30 bis 40 von 7583.

          Um die 7583 geht es mir.

          Grüße

          Tom

      2. Hallo!

        Genau das ist das Problem. Wieviel Datensätze sind es zum Zeitpunkt der Abfrage?

        Genau wie Du es schon geschrieben hast!

        SELECT COUNT(*) FROM tabelle;

        Eben nicht. Es hndelt sich um eine Bewegungsdatentabelle und keine Stammdatentabelle. Da ändert sich sekündlich was. Ich kann dem Operator also nicht einfach seinen "nächste Seite" Button wegnehmen. Ich muss nur verhindern, dass er über die obere Query-Border hinauszählt.

        Mein Beispiel (Punkt 1-3) wird auf jeder Seite wiederholt. Also bei jedem Aufruf wird sich die Anzahl der Datensätze geholt.

        Doch, in Mikrosekunden lässt sich das messen.

        Kommt pro Milisekunde ein neuer Datensatz hinzu?

        MfG, André Laugks

        --
        L-Andre @ gmx.de
        1. Hello,

          Genau das ist das Problem. Wieviel Datensätze sind es zum Zeitpunkt der Abfrage?

          Genau wie Du es schon geschrieben hast!

          SELECT COUNT(*) FROM tabelle;

          Was fasst MySQL dann an Daten an, wenn am den Stern in die Count-Anweisung nimmt, statt eines Feldes?

          Doch, in Mikrosekunden lässt sich das messen.

          Kommt pro Milisekunde ein neuer Datensatz hinzu?

          ich rechne in der Tabelle mit 40.000 Bewegungen pro Tag. das wären 27 pro Sekunde.

          Grüße

          Tom

          1. Hallo!

            Was fasst MySQL dann an Daten an, wenn am den Stern in die Count-Anweisung nimmt, statt eines Feldes?

            Im Prinzip irgendeine Spalte.

            ich rechne in der Tabelle mit 40.000 Bewegungen pro Tag. das wären 27 pro Sekunde.

            Das sollten aber alle 2,16 Sekunden ein Datensatz sein.

            MfG, André Laugks

            --
            L-Andre @ gmx.de
            1. Hello,

              ich rechne in der Tabelle mit 40.000 Bewegungen pro Tag. das wären 27 pro Sekunde.

              Das sollten aber alle 2,16 Sekunden ein Datensatz sein.

              Scheint zu stimmen, habe ich wohl einmal zuwenig durch 60 geteilt *umpf*

              Trotzdem noch mehr als mir lieb ist. Zum Glück müssen wir ja nicht alle 40.000 Bewegungen anschauen, sondern nur einen Teil davon. ABer 500-1000 am Tag können das immer noch werden.

              Grüße

              Tom

            2. Hallo André!

              ich rechne in der Tabelle mit 40.000 Bewegungen pro Tag. das wären 27 pro Sekunde.

              Das sollten aber alle 2,16 Sekunden ein Datensatz sein.

              40 000 / 24 / 60 / 60 = 0,46
              Zahl     h    m    s

              Alles 0,46s ein Datensatz. ;-)

              Bye,
              Peter

  3. Moin!

    Was aber macht man am hinteren Ende, damit man nicht über's Ziel hinausschießt. Es gibt ja den bekannten Trick, einfach einen Satz mehr abzufragen (also $limit + 1) und wenn der nicht mehr da ist, kein "Vorwärts" mehr anzubieten. Aber das ist mir mal wieder zu unsicher in dynamischen Datenbeständen. Es könnten ja seit dem letzten am hinteren Anschlag Angekommen sein Datensätze hinzugekommen sein (durch andere User).

    Ja, und? Du hast bei dynamischen Datenbanken _immer_ das Problem, dass die generierte und im Browser angezeigte Sicht eben nur dem Stand zum Zeitpunkt der Abfrage entspricht, und spätere Änderungen in der Datenbank nicht auf magische Weise zum Browser gelangen.

    Wenn man am hinteren Ende nicht mehr weiterblättern kann, und neue Datensätze hinzukommen, hilft ein Reload, und schon kann man weiterblättern.

    Du ignorierst übrigens ja auch das Problem, dass - abgängig von der Sortierung - mittendrin neue Datensätze entstehen könnten, die der Blätterer nicht sieht.

    Allerdings: Wenn du tatsächlich 40.000 Bewegungen pro Tag erwartest, dann ist ein "Blättern", wie auch immer es realisiert wird, für die Benutzer nicht zielführend. Es ist schlichtweg unmöglich, in großen Datenbanken zu "blättern" wie in einem Karteikasten. Und auch in einem Karteikasten "blättert" man nicht, um den Gesamtbestand durchzugehen, sondern man sucht gezielt einen oder wenige Datensätze, um sie zu lesen oder zu ändern.

    Biete den Benutzern eine sinnvolle, zielführende Abfragemaske für die Datenbank an, damit diese schnell zu ihrem Datensatz kommen. Es ist bei sowas wenig hilfreich, beispielsweise alle dreitausens "Meier" als durchblätterbare Seiten aufzulisten. Das blättert niemand durch, sondern wird im Zweifelsfall den Vornamen, das Geburtsdatum oder den Wohnort zu Hilfe nehmen, um die Suche weiter einzugrenzen. Die Mitgliedsnummer würde natürlich auch helfen. :)

    Welches Statement würdet Ihr benutzen um nun vorab nur die Geamtanzahl der dem Filterkriterium (wahrscheilich "where ...") entsprechenden Datensätze herauszufinden. Felder benötigt man ja eigentlich nicht.

    Select count(ID)from table where...;

    Ist das das performanteste, was man sich denken könnte?

    Wenn du zwingend die Gesamtzahl aller Datensätze benötigst, dann ist das das schnellste, was geht.

    Allerdings: Auch für diese Gesamtzahl gilt natürlich, dass sie im Moment der Abfrage schon wieder veraltet ist und nachfolgende neue Datensätze nicht anzeigt.

    Insofern ist es eben vollkommen egal, ob dein "Weiterblättern"-Button nun aufgrund des fehlenden überzähligen Datensatzes nicht angezeigt wird, oder aufgrund der absolut ermittelten Datensatzzahl. Das Ergebnis ist dasselbe - und bei der einen Methode weiß der Benutzer, was er geleistet hat, wenn er 30.000 Datensätze durchblättert hat und am Ende angekommen ist. ;)

    Eine kleine Unsicherheit gibt's dann ja trotzdem noch, weil zwischen dem Zähl-Select und dem gefüllten mit limit auch wieder Zeit vergeht. Aber damit könnte man leben, da das ja erst relevant wird, wenn $offset > $count werden würde.

    Wenn du die absolute Zahl an Datensätzen weißt, kannst du eine Seitensprungnavigation anbieten. Diese wäre umso hilfreicher, wenn sie nicht nur die Seiten durchnumerieren würde, sondern (damit man nicht durch Seitenaufruftaktik wie Intervallhalbierung trotzdem noch suchen muß) ein relevantes Kriterium (bei einer Namenssuche beispielsweise ein Namensfragment - genau wie beim Telefonbuch oder beim mehrbändigen Lexikon das "Mei - Mue", "Mue - Nas"...) ausgeben würde.

    - Sven Rautenberg

    --
    "Beim Stuff für's Web gibts kein Material, was sonst das Zeugs ist, aus dem die Sachen sind."
    (fastix®, 13. Oktober 2003, 02:26 Uhr -> </archiv/2003/10/60137/#m338340>)
    1. Hello Sven,

      natürlich lasse ich nicht alle Bewegungen anzeigen, sondern nur die relavanten. Aber die verstecken sich eben zwischen den 40.000.

      Nachdem das Problem mit der oberen Schranke sich geklärt hatte (mysql_num_rows() ist dann eben kliener als $limit) bleibt nur noch die Frage nach dem Unterschied zwischen

      Select count(ID)from table where...;
      Select count(*)from table where...;

      wobei ID hier der Primärschlüssel ist. Es könnte acuh jedes andere Feld benutz werden. Ich will ja aber gar kein Resultset, sondern nur das Zählergebnis für die Filterbedingung. Und dafür möchte ich MySQL eben so wenig wie möglich arbeiten lassen.

      Allerdings: Auch für diese Gesamtzahl gilt natürlich, dass sie im Moment der Abfrage schon wieder veraltet ist und nachfolgende neue Datensätze nicht anzeigt.

      Ja, das kann man durch einen neuen Blätterversuch dann eben feststellen. Bei Sortierung "Timestamp" sind die neuesten Sätze ja sowieso immer am Ende. Ist nur blöd, wenn dann zwischendurch welche gelöscht werden. Dafür registriere ich bei Nutzung einer von der ID abweichenden Sortierung einen Aufsetzpunkt (where $intro > $checkpoint) und setze $offset auf 0 zurück. Diese Thematik hatten wir schon einmal. $intro besteht aus dem Sortier-Feld und der autoincrement-ID. Auch Timestamp ist bei 30 Bewegungen pro Sekunde ja leider nicht mehr unär.

      So langsam bekomme ich da polymorphe Strukturen, sodass meine Funktionen allgemeinverwendbar werden.

      Bleibt noch mein Problem, ob und wie man der Satzbeschreibung von MySQL eigene Kriterien hinterlegen könnte. Aber das Extra-Feld ist wohl nicht für den DB-Entwickler selber nutzbar. Das wäre nämlich klasse. Wie könnte man denn bei Version 3.23.55-max sonst die Relationen vermerken.

      Ich behelfe mir im Moment über den Feldnamen. "ID_ADRESSE" bedeutet dann eben eine Relation zur Tabelle ADRESSE, wobei man ja leider nicht weiß, welcher Art sie ist (1:1, 1:n, n:1) und ob refenzielle Integrität gewahrt bleiben muss.

      Schönen Sonntag noch

      Tom

      1. Moin!

        Nachdem das Problem mit der oberen Schranke sich geklärt hatte (mysql_num_rows() ist dann eben kliener als $limit) bleibt nur noch die Frage nach dem Unterschied zwischen

        Select count(ID)from table where...;
        Select count(*)from table where...;

        Ausprobieren. count() kann bei so simplen Abfragen optimiert werden (IIRC), es macht daher Sinn, eine indizierte Spalte in WHERE abzufragen und diese dann auch als count()-Argument zu verwenden.

        Allerdings: Auch für diese Gesamtzahl gilt natürlich, dass sie im Moment der Abfrage schon wieder veraltet ist und nachfolgende neue Datensätze nicht anzeigt.

        Ja, das kann man durch einen neuen Blätterversuch dann eben feststellen.

        Und genau diese Tatsache unterscheidet beide Varianten kein bißchen voneinander.

        Bei Sortierung "Timestamp" sind die neuesten Sätze ja sowieso immer am Ende. Ist nur blöd, wenn dann zwischendurch welche gelöscht werden. Dafür registriere ich bei Nutzung einer von der ID abweichenden Sortierung einen Aufsetzpunkt (where $intro > $checkpoint) und setze $offset auf 0 zurück. Diese Thematik hatten wir schon einmal. $intro besteht aus dem Sortier-Feld und der autoincrement-ID. Auch Timestamp ist bei 30 Bewegungen pro Sekunde ja leider nicht mehr unär.

        Du meinst "unique"? :)

        Ich sehe deine Lösung nicht. Neue und geänderte Datensätze kriegen einen aktuellen Timestamp und werden in der Sortierung "hinten" angezeigt. Gelöschte Datensätze werden überhaupt nicht mehr angezeigt (die sind ja gelöscht).

        Gegen das Nichtanzeigen gelöschter Datensätze hilft, sie nicht wirklich mit DELETE zu löschen, sondern nur als "gelöscht" zu kennzeichnen. Dann haben sie natürlich wieder ein Timestamp, welches aktualisiert wird.

        Aber gegen geänderte Datensätze hilft absolut nichts.

        Mal angenommen, du listest 10 Datensätze pro Seite und hast insgesamt 14 Datensätze. Du zeigst Seite 1 an. Alles ist wunderbar. Dann werden 4 Datensätze dieser Seite geändert. Dann blätterst du auf Seite 2. Dort kriegst du exakt die 4 geänderten Datensätze gezeigt. Die 4 Sätze, die vorher dort gewesen waren, sind aufgrund deiner Timestamp-Sortierung auf Seite 1 gewandert, wurden also nie angezeigt.

        Wie willst du verhindern, dass sowas passiert? Wenn du hierfür eine schlüssige, funktionierende Lösung anbieten kannst, dann bist du wirklich gut. Mir ist für dieses Problem nämlich nur die Ausweichlösung eingefallen, es gar nicht erst zu einem Problem werden zu lassen, sondern eben zu akzeptieren, dass bei einem Client-Server/Client-Server-System, wie es von Browser-PHP-MySQL dargestellt wird, unmöglich ist, Aktualisierungen in der Datenbank sofort zum Anzeigeclient zu senden, damit dieser reagieren und die Anzeige aktualisieren kann.

        Denn üblicherweise treten solche Aktualitätsprobleme deshalb auf, weil in der Datenbank viele Änderungen stattfinden. Und weil Datenbanken mit vielen Änderungen typischerweise nicht sinnvoll durchzublättern sind, weil sie meist auch riesengroß sind, entfällt das Problem auf elegante Weise. Oder man akzeptiert und berücksichtigt eben, dass die angezeigte Darstellung nicht aktuell sein muß, und läßt sich im Zweifel eben eine neue Seite generieren.

        So langsam bekomme ich da polymorphe Strukturen, sodass meine Funktionen allgemeinverwendbar werden.

        Ich glaube nicht.

        Bleibt noch mein Problem, ob und wie man der Satzbeschreibung von MySQL eigene Kriterien hinterlegen könnte. Aber das Extra-Feld ist wohl nicht für den DB-Entwickler selber nutzbar. Das wäre nämlich klasse. Wie könnte man denn bei Version 3.23.55-max sonst die Relationen vermerken.

        Gar nicht. MySQL 3 kennt keine foreign keys, es ist Aufgabe des Programmierers, die Relationen herzustellen und synchron zu halten. Insofern weiß man deine Relationen nur aufgrund deines irgendwo aufgemalten DB-Schemas - oder man vermutet sie aufgrund geschickt gewählter Feldnamen.

        Ich behelfe mir im Moment über den Feldnamen. "ID_ADRESSE" bedeutet dann eben eine Relation zur Tabelle ADRESSE, wobei man ja leider nicht weiß, welcher Art sie ist (1:1, 1:n, n:1) und ob refenzielle Integrität gewahrt bleiben muss.

        Tja, falsche Datenbank für diese Anforderung, würde ich sagen.

        - Sven Rautenberg

        --
        "Beim Stuff für's Web gibts kein Material, was sonst das Zeugs ist, aus dem die Sachen sind."
        (fastix®, 13. Oktober 2003, 02:26 Uhr -> </archiv/2003/10/60137/#m338340>)
        1. Hello,

          Du meinst "unique"? :)

          Gut, unäres Feld mit eineindeutigem Schlüssel, bzw. der Schlüssel ist gerade nicht mehr primär.

          Gegen das Nichtanzeigen gelöschter Datensätze hilft, sie nicht wirklich mit DELETE zu löschen, sondern nur als "gelöscht" zu kennzeichnen. Dann haben sie natürlich wieder ein Timestamp, welches aktualisiert wird.

          Das muss ich mir sowieso noch überlegen, ob das nicht aus rechtlichen Gründen demnächst vorgeschrieben ist. Aber eine vollständige Historie kann man nicht speichern. Bis ein User mit dem Inhalt seiner Seite zufrieden ist, wird die oft 20-30mal geändert.

          Aber gegen geänderte Datensätze hilft absolut nichts.

          Doch, die haben dann ja einen neunen Timestamp in der Liste "letzte Veränderungen"

          Mal angenommen, du listest 10 Datensätze pro Seite und hast insgesamt 14 Datensätze. Du zeigst Seite 1 an. Alles ist wunderbar. Dann werden 4 Datensätze dieser Seite geändert. Dann blätterst du auf Seite 2. Dort kriegst du exakt die 4 geänderten Datensätze gezeigt. Die 4 Sätze, die vorher dort gewesen waren, sind aufgrund deiner Timestamp-Sortierung auf Seite 1 gewandert, wurden also nie angezeigt.

          Nein, die sind ja noch nicht angezeigt worden, also liegen sie im Query noch über dem Aufsetzpunkt (Timestamp + ID). Wenn ich stur Offset und Limit benutzen würde, dann hättest Du (glaube ich) Recht.
          Das ist ja genau das Thema, dass wir schon einmal hatten. Irgendwann wird doch noch ein Featureartikel daraus: "Strukturiertes Arbeiten in dynamischen Datenbeständen" Unterkapitel: "Blättern"

          Wie willst du verhindern, dass sowas passiert? Wenn du hierfür eine schlüssige, funktionierende Lösung anbieten kannst, dann bist du wirklich gut. Mir ist für dieses Problem nämlich nur die Ausweichlösung eingefallen, es gar nicht erst zu einem Problem werden zu lassen, sondern eben zu akzeptieren, dass bei einem Client-Server/Client-Server-System, wie es von Browser-PHP-MySQL dargestellt wird, unmöglich ist, Aktualisierungen in der Datenbank sofort zum Anzeigeclient zu senden, damit dieser reagieren und die Anzeige aktualisieren kann.

          Ich denke schon sehr lange über solche Probleme nach und habe auch schon die verschiedensten Lösungen entwickelt (und verkauft) aber eben noch nicht für "Internettechnologie". Das Problem hier ist, dass kein Messaging (Serverpush) über den Netzwerksocket des Clients möglich ist.

          Tja, falsche Datenbank für diese Anforderung, würde ich sagen.

          Da magst Du auch wieder recht haben. Ich vergleiche immer gerne mit den Möglichkeiten von Informix. Aber das wollen dann eben viele Kunden nicht einkaufen.

          Grüße

          Tom

          1. Moin!

            Mal angenommen, du listest 10 Datensätze pro Seite und hast insgesamt 14 Datensätze. Du zeigst Seite 1 an. Alles ist wunderbar. Dann werden 4 Datensätze dieser Seite geändert. Dann blätterst du auf Seite 2. Dort kriegst du exakt die 4 geänderten Datensätze gezeigt. Die 4 Sätze, die vorher dort gewesen waren, sind aufgrund deiner Timestamp-Sortierung auf Seite 1 gewandert, wurden also nie angezeigt.

            Nein, die sind ja noch nicht angezeigt worden, also liegen sie im Query noch über dem Aufsetzpunkt (Timestamp + ID). Wenn ich stur Offset und Limit benutzen würde, dann hättest Du (glaube ich) Recht.

            Falsch gedacht.

            Ich drösel das noch mal auf (und mach das Beispiel kleiner).

            Zustand vorher:
            id timestamp daten
             1  10:23     alt1
             2  10:24     alt2
             3  10:25     alt3
             4  10:25     alt4
            99  10:26     alt5

            Jetzt werden je Seite 3 Datensätze angezeigt. Also zuerst mal Seite 1:
            SELECT * FROM tabelle WHERE timestamp > 10:23 ORDER BY timestamp LIMIT 1,3
            id timestamp daten
             1  10:23     alt1
             2  10:24     alt2
             3  10:25     alt3

            Während der Benutzer diese Anzeige genießt, werden ein paar Änderungen eingespielt. Zustand der Tabelle danach:
            id timestamp daten
             1  11:13     neu1
             2  10:24     alt2
             3  10:25     alt3
             4  11:15     neu2
            99  10:26     alt5

            Und jetzt will der Benutzer Seite 2 sehen.
            SELECT * FROM tabelle WHERE timestamp > 10:23 ORDER BY timestamp LIMIT 4,3

            Das wäre die sortierte Tabelle:
            id timestamp daten
             2  10:24     alt2
             3  10:25     alt3
            99  10:26     alt5
             1  11:13     neu1
             4  11:15     neu2

            Und durch das Limit kriegst du das als Ergebnis:
            id timestamp daten
             1  11:13     neu1
             4  11:15     neu2

            Datensatz 1 hattest du aber schon gesehen. Datensatz 99 hingegen siehst du gar nicht.

            Ich denke schon sehr lange über solche Probleme nach und habe auch schon die verschiedensten Lösungen entwickelt (und verkauft) aber eben noch nicht für "Internettechnologie". Das Problem hier ist, dass kein Messaging (Serverpush) über den Netzwerksocket des Clients möglich ist.

            Genau das ist das Problem. Und es ist nicht lösbar.

            Und selbst wenn du mit der Timestamp arbeitest und die zuletzt angezeigte Timestamp, bzw. das bis dahin angezeigte Maximum der Timestamps speicherst, fallen dir eben beim Weiterblättern alle Einträge mit späteren Daten weg.

            Blättern ist eben im wörtlichen Sinne nicht möglich. Du kannst sehr wohl "aktualisierte Daten seit Datum X" anzeigen lassen. Alle untereinander aufgelistet. Und der Reload zeigt dann seit letztem Reload-Zeitpunkt neu hinzugekommene Daten. Wieder fein untereinander aufgelistet. Wenn du viele Datenbankbewegungen hast, wird das aber schnell lang und unübersichtlich. Dann kannst du für "echtes" Blättern eigentlich nur DHTML benutzen, indem du die lange Liste in handliche Häppchen aufteilst und das Blättern auf dem Client erledigst. Das Problem ist dann eben, dass sich die angezeigten Datensätze währenddessen ändern können. Zur simplen Ansicht ist das kein Problem - es wird spannender, wenn der Client auch was ändern können soll. Dann wirst du um ein Locking des Datensatzes nicht herumkommen, oder um ausgefeilte DIFF/Merge-Techniken.

            - Sven Rautenberg

            --
            "Beim Stuff für's Web gibts kein Material, was sonst das Zeugs ist, aus dem die Sachen sind."
            (fastix®, 13. Oktober 2003, 02:26 Uhr -> </archiv/2003/10/60137/#m338340>)
            1. Hello,

              Genau das ist das Problem. Und es ist nicht lösbar.

              Genau das Problem habe ich dadurch gelöst, dass ich mir den Einsprungspunkt jeder Seite merke und Offset jedes Mal auf 0 zurücksetze. Man fängt dann quasi vom Einsprungspunkt wieder von vorne an.

              Der Einsprungspunkt lt. Filterbedingung muss entweder ein Primärschlüssel sein, oder durch zusätzliche Maßnahmen dazu gemacht werden. Das kann man z.B. ereichen, indem man einen Index über den Namen (Meier) und die ID des Datensatzes aufbaut.

              Natürlich nur, wenn man nach dem Namen sucht.

              Wenn man nach der letzten Veränderung sucht muss man dann eben LastUpdate + ID nehmen.

              Wichtig ist eigentlich nur, dass auch bei Duplicates des Suchbegriffes der Kombinationsschlüssel aus diesem und einer Hilfsgröße immer unique *g* bleibt.

              Irgendwann werde ich das ja mal fertig haben... dann kommt der Bericht

              Grüße

              Tom

              1. Moin!

                Genau das Problem habe ich dadurch gelöst, dass ich mir den Einsprungspunkt jeder Seite merke und Offset jedes Mal auf 0 zurücksetze. Man fängt dann quasi vom Einsprungspunkt wieder von vorne an.

                Ich verstehe nicht, was du machst. Würdest du das nochmal anhand eines Beispieles erläutern?

                - Sven Rautenberg

                --
                "Beim Stuff für's Web gibts kein Material, was sonst das Zeugs ist, aus dem die Sachen sind."
                (fastix®, 13. Oktober 2003, 02:26 Uhr -> </archiv/2003/10/60137/#m338340>)
                1. Hello Sven,

                  Ich verstehe nicht, was du machst. Würdest du das nochmal anhand eines Beispieles erläutern?

                  Ja, gerne. Aber nicht jetzt. Denn jetzt ging es nur um die "einfache Variante". Und dazu müsste ich nur wissen, was man bei Select count() alles falsch machen kann, um die Performance zu killen.

                  Ich werde das ganz bestimmt nicht aus dem Auge verlieren, und zum Rest noch ausführlich Stellung nehmen.

                  Grüße

                  Tom