Was sind die praktischen Unterschiede zwischen "REPLACE" und "INSERT ... ON DUPLICATE KEY UPDATE" in MySQL?

79

Ich muss die Werte aller Felder eines Datensatzes mit einem bestimmten Schlüssel festlegen (der Schlüssel ist tatsächlich zusammengesetzt) ​​und den Datensatz einfügen, wenn noch kein Datensatz mit einem solchen Schlüssel vorhanden ist.

REPLACEscheint wie gedacht, um die Arbeit zu erledigen, aber gleichzeitig schlägt seine Handbuchseite vor INSERT ... ON DUPLICATE KEY UPDATE.

Welchen von ihnen sollte ich besser wählen und warum?

Der einzige "Nebeneffekt", der REPLACEmir in den Sinn kommt, ist, dass dadurch die Autoinkrementierungswerte erhöht werden (zum Glück verwende ich keine), während dies INSERT ... ON DUPLICATE KEY UPDATEwahrscheinlich nicht der Fall ist . Was sind die anderen praktischen Unterschiede zu beachten? In welchen besonderen Fällen kann REPLACEman es vorziehen INSERT ... ON DUPLICATE KEY UPDATEund umgekehrt?

Ivan
quelle
INSERT ... ON DUPLICATE KEY UPDATE erhöht tatsächlich auch den Autoincrement-Zähler. Nicht für den zu aktualisierenden Datensatz, sondern für den nächsten eingefügten Datensatz. Wenn also die höchste ID 10 ist und Sie eine doppelte Einfügung durchführen und dann einen neuen eindeutigen Wert einfügen, wird die ID dieser Zeile zu 12.
marlar

Antworten:

113

REPLACEführt intern ein Löschen und dann ein Einfügen durch. Dies kann zu Problemen führen, wenn eine Fremdschlüsseleinschränkung auf diese Zeile zeigt. In dieser Situation kann REPLACEdies fehlschlagen oder schlimmer sein: Wenn Ihr Fremdschlüssel auf Kaskadenlöschung eingestellt ist, REPLACEwerden Zeilen aus anderen Tabellen gelöscht. Dies kann passieren, obwohl die Einschränkung sowohl vor als auch nach der REPLACEOperation erfüllt wurde .

Die Verwendung INSERT ... ON DUPLICATE KEY UPDATEvermeidet dieses Problem und wird daher bevorzugt.

Mark Byers
quelle
1
Gute Antwort, aber im konkreten Fall von mir wird dieses Problem nicht gelöst. Die Wahrscheinlichkeit einer Kollision kann jedoch als 50/50 angesehen werden. Was soll ich dann wählen? Und wie INSERT ... ON DUPLICATE KEY UPDATEsieht es deutlich "besser" aus? In welchen Fällen kann "ERSETZEN" eine bessere Wahl sein?
Ivan
3
Ich habe einiges recherchiert und soweit ich das beurteilen kann, gibt es keinen gemeinsamen Grund, REPLACE anstelle von INSERT ... ON DUPLICATE KEY UPDATE zu verwenden. Es ist im Wesentlichen eine Legacy-Funktion. Sofern es keinen bestimmten Grund gibt, warum Ihr Code darauf beruht, dass Zeilen gelöscht und erneut hinzugefügt werden, mit den damit verbundenen Auswirkungen auf Indizes und Werte für die automatische Inkrementierung, scheint es keinen Grund zu geben, ihn zu verwenden.
Nathan Stretch
2
On REPLACEaktualisiert Ihren PK-Auto-Inkrement-Wert, wenn a DELETEund ausgeführt werden INSERT. Welches ist genau das, was ich will. Ich möchte nicht, dass der Verbraucher den Datensatz unter derselben PK findet, damit er keine Zeilen erhält. Wenn ich möchte, dass sie es finden (aktuelles Update), benutze ichUPDATE
radtek
So ist die andere Hälfte der Frage: Wann wollen Sie REPLACEüber INSERT ... ON DUPLICATE KEY UPDATE? Warum sollte ein INSERT+ DELETEjemals einem vorgezogen werden UPDATE?
LemonPi
58

Um die Frage nach der Leistung zu beantworten, habe ich einen Test mit beiden Methoden durchgeführt

Ersetzen In beinhaltet:
1.Try Einsatz auf dem Tisch
2. Wenn 1 ausfällt, Zeile löschen und einfügen neue Zeile

einfügen auf Duplizieren Key Update beinhaltet:
1.Try Einsatz auf dem Tisch
2.Falls 1 ausfällt, update Reihe

Würde man alle beteiligten Schritte sind Einsätze sollte es keinen Leistungsunterschied geben. Die Geschwindigkeit muss von der Anzahl der Aktualisierungen abhängen. Der schlimmste Fall ist, wenn alle Anweisungen aktualisiert werden

Ich habe beide Anweisungen in meiner InnoDB-Tabelle mit 62.510 Einträgen (nur Aktualisierungen) ausprobiert. Bei Camparing-Geschwindigkeiten:
Ersetzen in: 77,411 Sekunden
Einfügen bei doppelter Schlüsselaktualisierung: 2,446 Sekunden

Insert on Duplicate Key update is almost 32 times faster.

Tabellengröße: 1.249.250 Zeilen mit 12 Spalten auf einem Amazon m3.medium

katrix
quelle
Coole Statistiken, hast du es versucht Insert on Duplicate Key Replace? War es langsamer?
Radtek
9

Bei Verwendung von REPLACEanstelle von INSERT ... ON DUPLICATE KEY UPDATEstelle ich manchmal Probleme mit der Schlüsselsperre oder dem Deadlock fest, wenn mehrere Abfragen für einen bestimmten Schlüssel schnell eingehen. Die Atomizität des letzteren (zusätzlich dazu, dass keine Kaskadenlöschungen verursacht werden) ist umso mehr ein Grund, es zu verwenden.

Andrew Mao
quelle
3

Wenn Sie nicht alle Spalten auflisten, REPLACEwerden alle nicht erwähnten Spalten mit ihren Standardwerten in den ersetzten Zeilen zurückgesetzt. ON DUPLICATE KEY UPDATElässt nicht erwähnte Spalten unverändert.

Barmar
quelle
3

In welchen besonderen Fällen kann REPLACE gegenüber INSERT ... ON DUPLICATE KEY UPDATE bevorzugt werden und umgekehrt?

Ich habe gerade herausgefunden, wie schwierig es ist, bei Tabellen mit einer FEDERATED-Speicher-Engine INSERT...ON DUPLICATE KEY UPDATEAnweisungen zu akzeptieren, die jedoch fehlschlagen (mit einem Fehler 1022: Kann nicht schreiben; Schlüssel in Tabelle duplizieren ...), wenn ein Schlüssel dupliziert wird Es tritt ein Verstoß auf - siehe den entsprechenden Aufzählungspunkt auf dieser Seite des MySQL-Referenzhandbuchs.

Glücklicherweise konnte ich REPLACEanstelle INSERT...ON DUPLICATE KEY UPDATEmeines After-Insert-Triggers das gewünschte Ergebnis beim Replizieren von Änderungen in einer FEDERATED-Tabelle verwenden.

w5m
quelle
2

Ersetzen scheint zwei Operationen auszuführen, falls der Schlüssel bereits vorhanden ist. Vielleicht impliziert das, dass es einen Geschwindigkeitsunterschied zwischen den beiden gibt?

(INSERT) ein Update gegen ein Delete + ein Insert (REPLACE)

EDIT: Meine Implikation, dass das Ersetzen langsamer sein könnte, ist eigentlich völlig falsch. Nun, laut diesem Blog-Beitrag sowieso ... http://www.tokutek.com/2010/07/why-insert-on-duplicate-key-update-may-be-slow-by-incurring-disk-seeks /.

Isaac Fife
quelle
0

REPLACE scheint manchmal notwendig zu sein, da INSERT IGNORE nicht mit Datentransformationen zu funktionieren scheint.

Wenn ich das mache, setze ich nur largeCityPop auf sich selbst:

INSERT IGNORE IN größte Städte (stateID, größteCityPop, statePop) SELECT stateID, MAX (city.pop) als größteCityPop, state.pop FROM Stadt JOIN Zustand auf city.stateID = state.ID GRUPPE NACH city.stateID ON DUPLICATE KEY UPDATE größteCityPop = größteCityPop

In diesem Fall verwende ich die GROUP-Funktion nicht ordnungsgemäß:

INSERT IGNORE IN größterCities (stateID, größtesCityPop, statePop) SELECT stateID, MAX (city.pop) als größtesCityPop, state.pop FROM city JOIN state auf city.stateID = state.ID GRUPPE NACH city.stateID ON DUPLICATE KEY UPDATE größtesCityPop = MAX (city.pop)

Und wenn ich das mache, erkennt MySQL den Spaltennamen nicht:

INSERT IGNORE IN größterCities (stateID, größteCityPop, statePop) SELECT stateID, MAX (city.pop) als größtesCityPop, state.pop FROM city JOIN state auf city.stateID = state.ID GRUPPE NACH city.stateID ON DUPLICATE KEY UPDATE größteCityPop = Stadt .largestCityPop

Das funktioniert, scheint aber einfach hässlich:

INSERT IGNORE IN größte Städte (stateID, größteCityPop, statePop) SELECT * FROM (SELECT stateID, MAX (city.pop) als größteCityPop, state.pop FROM Stadt JOIN state auf city.stateID = state.ID GROUP BY city.stateID) x ON DUPLICATE KEY UPDATE größtesCityPop = größtesCityPop

Dan Marsh
quelle