suit: MySQL: INSERT, bei bestehendem Key bestehenden Wert lesen

Hallo,

ich habe eine MySQL[1]-Tabelle die aktuell etwa folgendermaßen aussieht:

id | foo | bar
---+-----+-----
1  | val | val2
2  | val | val2

Nun habe ich PHP-Array welches entsprechend einem Datensatz aufgebaut ist:

[id] = 3
[foo] = val
[bar] = val2

Das soll mit den Werten in der Datenbank abgeglichen werden - id ist dabei das Eindeutigkeitskriterium.

Aktuell sieht das so aus:

SELECT auf die Tabelle anhand der ID des Arrays.

Sofern ID existiert und ein Datensatz bzw eine Ergebnismenge zurückgeliefert wird, wird das Array verworfen und gegen die Werte aus der Datenbank ersetzt. Wenn die ID noch nicht existiert, wird das Array per INSERT in die Datenbank geschrieben.

Bei einem neuen Eintrag ist also eine Abfrage notwendig, bei einem bestehenden Eintrag sind zwei notwendig - der Regelfall ist, dass der Eintrag schon besteht. Darum gibt es, eine Abfrage einzusparen.

Die Frage nun: gibt es in MySQL[1] eine Möglichkeit, dies mit nur einer Abfrage zu leisten. Ich stelle mir hierzu etwas in die Richtung "INSERT ... ON DUPLICATE KEY UPDATE" vor - nur eben, dass bei doppelten Key nicht upgedatet sondern der bestehende Wert gleich gelesen wird.

Der Hintergrund ist eine Mikrooptimierung - dieses Script MUSS bei jedem Seitenaufruf laufen - der Datebankserver ist allerdings extern und reagiert nicht grade sehr flott - eine Abfrage weniger würde hier bereits viel Ausmachen - etwa 10% der Zeit des Parsens.

Die alternative ist, auf die Datenbank teilweise zu verzichten und die Daten in einem Cookie abzulegen - das möchte ich aber nach Möglichkeit vermeiden.

[1] MySQL ist ein Must-Have-Kriterium - die Sache läuft über eine Abstraktionsschicht die prinzipiell auch andere RDBMS unterstützt, das ist aktuell aber nicht von belang - wäre aber wünschenswert.

  1. Hi!

    Sofern ID existiert und ein Datensatz bzw eine Ergebnismenge zurückgeliefert wird, wird das Array verworfen und gegen die Werte aus der Datenbank ersetzt. Wenn die ID noch nicht existiert, wird das Array per INSERT in die Datenbank geschrieben.

    Und zwischen Abfrage und Einfügen können andere Prozesse dazwischenfunken, wenn du keine Sperren verwendest. Schon deshalb ist dieses Vorgehen so nicht empfehlenswert.

    Bei einem neuen Eintrag ist also eine Abfrage notwendig, bei einem bestehenden Eintrag sind zwei notwendig - der Regelfall ist, dass der Eintrag schon besteht. Darum gibt es, eine Abfrage einzusparen.
    Die Frage nun: gibt es in MySQL[1] eine Möglichkeit, dies mit nur einer Abfrage zu leisten. Ich stelle mir hierzu etwas in die Richtung "INSERT ... ON DUPLICATE KEY UPDATE" vor - nur eben, dass bei doppelten Key nicht upgedatet sondern der bestehende Wert gleich gelesen wird.

    Versuche den Datensatz mit einem normalen INSERT einzufügen. Im Falle einer Schlüsselverletzung gibt es einen Fehler, den du abfangen musst. In dem Fall kannst du dann ein SELECT hinterherschicken, das die vorhandenen Daten abfragt. Damit ist zwar das TOCTOU-Problem gelöst, jedoch hast du nun im Regelfall zwei Abfragen statt einer. Dieses Problem lässt sich allein mit RUDI-Statements nicht lösen, aber es gibt ja Stored Procedures.

    Lo!

    1. Und zwischen Abfrage und Einfügen können andere Prozesse dazwischenfunken, wenn du keine Sperren verwendest. Schon deshalb ist dieses Vorgehen so nicht empfehlenswert.

      Gutes Argument.

      Dieses Problem lässt sich allein mit RUDI-Statements nicht lösen, aber es gibt ja Stored Procedures.

      Stored Procedures sind für mich böhmische Dörfer - hast du ggf. ein praktisches Beispiel, welches in die Richtung meiner Fragestellung geht zur Hand?

      1. Hi!

        Stored Procedures sind für mich böhmische Dörfer - hast du ggf. ein praktisches Beispiel, welches in die Richtung meiner Fragestellung geht zur Hand?

        Nur Übung macht aus einem Buch mit sieben Siegeln ein Boot mit sieben Segeln. Ich habe zu wenig Erfahrungen mit SP, um aus dem Handgelenk eine Lösung zu schütteln. Auf alle Fälle benötigst du Wissen im allgemeinen Umgang mit SPs, also wie man sie erstellt, wie man Parameter übergibt und wie man Ergebnisse bekommt. Diese gibt es als Ergebnismenge im Rückgabewert oder in einzelnen Werten über die Eingabeparameter. Du solltest/musst(?) dann auch eine aktuelle API verwenden, die mit SPs umgehen kann (also beispielsweise unter PHP mysqli statt mysql). Weiterhin wirst du einen Handler brauchen, der auf den Duplicate-Key-Fehler beim Einfügen reagiert. Alternativ kannst du auch mit Sperren und deinem ursprünglichen Ansatz arbeiten. Der Umfang des Codes in einer SP spielt ja weniger eine Rolle, wenn die allgemeine Responsibilität des DBMS auf Client-Anfragen (sprich: Roundtrip-Zeit) der Flaschenhals ist.

        Lo!

        1. Nur Übung macht aus einem Buch mit sieben Siegeln ein Boot mit sieben Segeln.

          Hab hier dieses "Segelhandbuch" gefunden, werde ich wohl bei Zeiten mal lesen http://www.tutorials.de/forum/sql-tutorials/179510-stored-procedures-mysql-5-a.html

          Danke vorerst für deine Hilfe.