MySQL - Autoincrement wird nicht sequentiell erhöht, wenn die letzte Zeile gelöscht wurde

8

Ich habe eine Tabelle, die eine automatisch inkrementierte Primärschlüssel-ID enthält. Wenn ich die letzte Zeile lösche (höchste ID, zum Beispiel ID = 6) und eine neue Zeile einfüge, beginnt die neue ID bei 7. Welchen Parameter muss ich ändern, damit der Primärschlüssel bei 6 beginnt?

CREATE TABLE animals (
 id MEDIUMINT NOT NULL AUTO_INCREMENT,
 name CHAR(30) NOT NULL,
 PRIMARY KEY (id)
) ENGINE=MyISAM;

INSERT INTO animals (name) VALUES
('dog'),('cat'),('penguin'),
('lax'),('whale'),('ostrich');

Ergebnis:
ID Name
1 Hund
2 Katze
3 Pinguin
4 Lax
5 Wal
6 Strauß

DELETE FROM animals WHERE id = 6;
INSERT INTO animals (name) VALUES
('x');

Ergebnis:
ID Name
1 Hund
2 Katze
3 Pinguin
4 Lax
5 Wal
7 x

Danke für den Rat.

Giordano
quelle
Was ist, wenn es Lücken gibt? (was aus mehreren anderen Gründen auftreten kann, nicht nur durch Löschen von Zeilen)
ypercubeᵀᴹ
Was möchten Sie tun, wenn das Löschen nach dem Einfügen erfolgt? Wirst du diese Lücke wiederverwenden? ist ja, dann denke ich nicht, dass Identität der richtige Typ für diese Spalte ist. Sie haben die Möglichkeit, sich keine Gedanken über eindeutige Werte in dieser Spalte zu machen. Wenn Sie beabsichtigen, die Werte in der Reihenfolge zu halten, können Sie auch den regulären Datentyp INT / BIGINT verwenden. Das Finden / Wiederverwenden / Zurücksetzen von Werten für jede fehlende Lücke ist wie der Verlust des Zwecks der Identitätseigenschaft.
Anup Shah
@giordano Warum willst du ein ordentlicher Freak von AUTO_INCREMENT PRIMARY KEY sein? Damit umgehen, gibt es auch eine "Lücke" in Ihren Tabellendaten, wenn Sie aufgrund von Fragmentierung aktualisieren / löschen.
Raymond Nijland
Ich habe vor einiger Zeit eine Untersuchung über kontinuierliche Auto_Increment-Werte für SQL Server durchgeführt: sqlity.net/de/792/the-gap-in-the-identity-value-sequence - Obwohl dies nicht für MySQL gilt, sind die zugrunde liegenden Mechanismen dieselben Sie erhalten also ähnliche Ergebnisse. Kurz gesagt, Sie können Lücken und automatisch generierte Sequenzen nicht verhindern.
Sebastian Meine
@ypercube: danke für die antworten. Die Lücke, die ich von einem anderen komplexeren Beispiel bekommen habe, aber ich wollte ein minimales Beispiel zeigen. Das eigentliche Beispiel war (1) Ändern des Ablaufdatums einer Zeile (z. B. aus einer Produkttabelle) aufgrund einer Änderung eines Attributs und (2) Hinzufügen des neuen Produkts mit demselben Produktcode, neuem Attribut, neuem Gültigkeitsdatum und offenem Ablaufdatum Datum. Was passiert ist, ist, dass der neue Primärschlüssel nicht automatisch mit +1, sondern mit +2 erhöht wurde. Offensichtlich gibt es in Schritt (1) oder (2) ein unsichtbares automatisches Inkrement. Ich frage mich, was der andere Grund für Lücken ist.
Giordano

Antworten:

12

Dies ist beabsichtigt - alle DBMS-Aktionen wurden mit Spalten für die automatische Inkrementierung ausgeführt.

Andernfalls könnte die externe referenzielle Integrität beschädigt werden. Stellen Sie sich als einfaches Beispiel vor, Sie speichern URLs für einen Verkürzungsdienst mit einer Spalte für die automatische Inkrementierung als Schlüssel. Sie wissen noch nicht, ob die verkürzte URL an jemanden weitergegeben wurde, und die Datenbank sicherlich nicht. Daher kann die Wiederverwendung der ID 1234 dazu führen, dass die arme Oma von jemandem somenastypornsite.xxx besucht, anstatt lovelyknitting.org, wenn sie auf http: / klickt /shortthi.ng/1234 in einer alten E-Mail, anstatt die Meldung "Entschuldigung, aber dieser Link ist in unseren Datensätzen nicht mehr vorhanden" zu erhalten.

Wenn Sie das Inkrement nach dem Löschen des letzten Elements zurücksetzen, werden Sie dann auch die ganze Arbeit (oder die Erwartung der Datenbank) durchlaufen, alles nach dem 5. Element von 5 Millionen neu zu nummerieren, wenn das 5. Element entfernt wird? komplett mit Änderungen an anderen Tabellen, bei denen Fremdschlüsseleinschränkungen auf die Inkrementspalte verweisen? Solche zusätzliche Arbeit könnte in Bezug auf E / A sehr teuer werden.

Wenn Sie tun , den Zuwachs Punkt zurückgesetzt , nachdem das letzte Element zu löschen, sei sehr , sehr vorsichtig Ihrer Transaktionsisolationsstufen: Sie setzen könnte es nur als eine andere Transaktion Fabrikaten der Wert verwenden, was zu Fehlern (oder noch schlimmer, leise Ausfälle), es sei denn , Sie stellen sicher, dass Ihre Aktion vollständig zu 100% isoliert ist.

Ich empfehle generell Leuten, die mit Datenbanken arbeiten, "SQL Antipatterns" zu lesen, das ein Kapitel zu diesem Thema mit dem Namen "Psuedo-Key Neat Freaks" enthält (das die Angelegenheit auf eine freundlichere Art und Weise behandelt, als der Kapiteltitel für manche vermuten lässt!). Wenn der Wert eine Bedeutung hat, die nicht nur ein Schlüssel ist (oder höchstens Informationen zur Einfügungsreihenfolge enthält), sollte er wahrscheinlich keine automatisch inkrementierende Spalte sein, und wenn er keine Bedeutung hat, die über die Bedeutung eines Schlüssels hinausgeht (oder höchstens eine Einfügereihenfolge enthält) Informationen) dann sollten Lücken keine Rolle spielen.

David Spillett
quelle
Danke für diese Erklärung. Ich sehe, dass ich tiefer in das Schlüsselkonzept eintauchen muss. Ich frage mich, wie der automatische Inkrementierungsmechanismus funktioniert, da ich auch Lücken im Primärschlüssel festgestellt habe, als ich ihn nicht gelöscht, sondern eine Zeile geändert (aktualisiert) und eine neue hinzugefügt habe. Was ich definitiv nicht tun werde, ist den automatischen Inkrementwert manuell zu ändern.
Giordano
In Bezug auf "tiefer in das Schlüsselkonzept eintauchen" empfehle ich dringend das SQL Antipatterns-Buch von Bill Karwin - es behandelt dieses und eine Reihe anderer allgemeiner (und nicht so häufiger) Themen und spricht darüber, wie man das Falsche versteht, warum das Gemeinsame Unrecht Methoden können Probleme verursachen, wie sie behoben werden können und wann die "falsche" Methode in Ordnung ist (oder die einzige Wahl), und zwar auf präzise, ​​aber leicht zugängliche Weise.
David Spillett
Spillet: Danke für diesen Hinweis. Ich habe jetzt gelesen und es war sehr hilfreich. Trotzdem verstehe ich nicht, warum InnoDB und MyISAM unterschiedlich zählen: dba.stackexchange.com/questions/51883/…
giordano
0

Sie können den Wert für auto_increment folgendermaßen zurücksetzen:

ALTER TABLE MyTable AUTO_INCREMENT = 1234;

Sie müssen den in der Tabelle vorhandenen Maximalwert ermitteln und diesem Wert 1 hinzufügen, um ihn in der obigen Anweisung zu verwenden.

Max Vernon
quelle
Schlechte Idee, dies verhindert, dass Ihre Tabelle in "fast allen" MySQL-Versionen gelesen oder geschrieben wird. MySQL 5.6 könnte ein LIVE ALTER ausführen, aber manchmal muss es auch die Tabelle sperren.
Raymond Nijland
2
@RaymondNijland Ich glaube nicht, dass das Schloss lange genug hält, damit es jemand bemerkt.
Ypercubeᵀᴹ
@ Max, Raymond, ypercube: Danke für die Antwort. Ich werde es vermeiden, diese Art von Veränderung vorzunehmen.
Giordano