Michael Neubert: MySQL Datenbankintegrität gefährdet?????????

Hallo,

beim Einfügen von Datensätzen in eine Tabelle einer MySQL Datenbank tritt bei mir in seltenen Fällen folgende Kuriosität auf, für die ich keine Erklärung habe:

Die Tabelle besteht aus zwei Feldern (Primärschlüssel id (integer) , Name varchar). Sie sieht z.B. folgendermaßen aus (Ausgabe unter phpMyAdmin):

id     Name
1      Tom
2      Klaus
3      Mike
4      Sven
5      Katja
6      Bernd
7      Micaela

Nach Einfügen eines weiteren Datensatzes kam es dann zu folgendem Effekt:

id     Name
1      Tom
2      Klaus
3      Mike
8      neuer Eintrag
4      Sven
5      Katja
6      Bernd
7      Micaela

Normalerweise hätte der neue Eintrag doch in der interen Darstellung der Tabelle an das Ende der Tabelle geschrieben werden müssen (Binärbaum).
Weitere Datensätze werden dann wieder korrekt an das Ende eingefügt. Der Fehler läßt sich zwar durch ein neues Sortieren der Tabelle (alter table...) beseitigen, aber dennoch mache ich mir Gedanken, wo der Fehler liegen könnte???????????????????????????

Hat irgendjemand dafür eine Erklärung????

Danke im Vorraus :-)

Micha

  1. Halihallo Michael

    Normalerweise hätte der neue Eintrag doch in der interen Darstellung der Tabelle an das Ende der Tabelle geschrieben werden müssen (Binärbaum).

    Nein. Weder ist die interne Darstellung einer Tabelle ein Binärbaum (das ist nur der
    Index, nicht aber die Daten), noch ist es normal, dass neue Einträge an das Ende ge-
    schreiben werden.

    Weitere Datensätze werden dann wieder korrekt an das Ende eingefügt. Der Fehler läßt sich zwar durch ein neues Sortieren der Tabelle (alter table...) beseitigen, aber dennoch mache ich mir Gedanken, wo der Fehler liegen könnte???????????????????????????

    Ganz einfach: Du löschst einen Datensatz, der wird intern als gelöscht markiert (braucht
    jedoch immer noch Speicherplatz). Wenn du nun einen neuen Datensatz speicherst, wird
    dieser nur bedingt am Ende angefügt (bedingt dann, wenn keine gelöschten Speicherstellen
    vorhanden sind). Wenn jedoch ein Datensatz zuvor gelöscht wurde, nimmt der neue Datensatz
    dessen Speicher in Anspruch. Ansonsten würde der Speicherverbrauch der Tabelle
    explodieren.

    Viele Grüsse

    Philipp

    1. Hallo Philipp,

      du hast recht. Durch das Löschen/Verkleiern von Einträgen wurde Speicherplatz freigegeben. Das erklärt alles :-)

      bye
      Micha

      1. Halihallo Michael

        du hast recht. Durch das Löschen/Verkleiern von Einträgen wurde Speicherplatz freigegeben. Das erklärt alles :-)

        Eben nicht ;)
        Durch das Löschen wird kein Speicherplatz freigegeben. Aber du meintest wohl, wenn du
        die Tabelle mit ALTER TABLE änderst, dann ja; wenn alle Daten sowieso geändert werden
        müssen, warum dann nicht auch die gelöschten auslassen.

        Aber wenn du nur an einer Speicherfreigabe interessierbar bist, solltest du wirklich

        OPTIMIZE TABLE tabelle

        benutzen.

        Viele Grüsse

        Philipp

  2. Halihallo Michael

    Normalerweise hätte der neue Eintrag doch in der interen Darstellung der Tabelle an das Ende der Tabelle geschrieben werden müssen (Binärbaum).
    Weitere Datensätze werden dann wieder korrekt an das Ende eingefügt. Der Fehler läßt sich zwar durch ein neues Sortieren der Tabelle (alter table...) beseitigen, aber dennoch mache ich mir Gedanken, wo der Fehler liegen könnte???????????????????????????

    Zuerst noch ein wenig mehr Ausführung, als beim ersten mal:
    Wenn ein Datensatz gelöscht wird, entsteht eine "Lücke" in der Datei. Wenn es nun in
    Dateien keine Lücken geben dürfte, müsste die _gesamte_ Datei (oder alles, was nach
    diesem Datensatz folgt) neu geschrieben werden, du kannst dir vorstellen, dass dies bei
    1'000'000 Datensätzen sehr, sehr viel Zeit kosten würde. Also hat man sich gedacht, OK,
    lassen wir die Lücke doch einfach frei und speichern dort einen neuen Datensatz ab.
    Dazu braucht es eine Statusangabe, die sagt: Datensatz existent oder Datensatz gelöscht.
    Wenn nun ein neuer Datensatz gespeichert werden soll, wird dieser nicht einfach an das
    Ende gehängt, sondern es wird erst versucht, Lücken wieder aufzufüllen (ansonsten würde
    die Datei ja immer länger werden).
    Es ist also keine Frage der Datenbankintegrität. Wenn du eine geordnete Liste ausgeben
    willst, musst du dies über Sortierung (ORDER BY) machen, ansonsten kannst du davon
    ausgehen, dass die Datensätze fern von jeglicher Logik oder Algorithmus ausgegeben
    werden (Datenbanken verwalten _Mengen_ (Multi-), nicht Listen, eine "Ordnung" gibt
    es nicht). Wenn du also eine geordnete Liste benötigst, _musst_ du ORDER BY verwenden.
    Zudem solltest du dich mit dem Begriff des Binärbaumes (AVL-Baum! - Nicht Binär-.)
    auseinandersetzen.

    So, und nun hab ich noch eine Frage:
    Wie wir festgestellt haben, muss es ein Status-Flag für jeden Datensatz geben, der u. a.
    die Information speichert, ob der Datensatz gelöscht wurde, oder nicht. Jetzt stellt sich
    mir die Frage, was wenn ein neuer Datensatz eingefügt wird? - Werden dann _alle_
    Datensätze (deren Stati) eingelesen (Full Table Scan), oder gibt es für diesen Datensatz-
    Status auch eine Art interner "Index"? - Wo werden diese "Status-Bytes" gespeichert,
    IMHO sinnvoll wäre es gleich bei den Daten (Datensatz mit zwei SMALLINT braucht demnach
    einfach 5 Bytes für die Daten, 2*2+1). Ist dies tabellentreiberspezifisch und bei jedem
    anders? - Ist dieses Status-Byte indiziert? - Habe dazu in der Doku (ich hab's mal für
    MySQL/ISAM gesucht) nicht's gefunden (kennt jemand die Stelle?).

    Viele Grüsse

    Philipp