SQL Verständnisfrage: paralleler Insert

Hallo,

nehmen wir an, es existiert folgende MySQL-Tabelle (test_tabelle):

Code:
| id | wert  |
|----|-------|
| 1  | alpha |
| 2  | beta  |
| 3  | gamma |

Über ein PHP Script wird an 2 voneinander unabhängigen Orten der Letzte Datensatz abgefragt (wert = gamma).
Eine IF-Abfrage prüft, ob der letzte Wert tatsächlich "gamma" ist und führt bei "true" ein Query (2 Mal) aus:

PHP:
if($wert=='gamma') {

mysql_query('INSERT INTO test_table (id, wert) VALUES ("4",  "delta");');

}

Meine Frage lautet: ist es theoretisch möglich, dass beide Inserts erfolgreich ausgeführt werden wenn das Script sozusagen an beiden Orten in der selben Nanosekunde aufgerufen wird, oder werden die SQL-Querys vom Server willkürlich in einer bestimmten Reihenfolge ausgeführt, so dass am Ende nur ein Query ausgeführt wird, weil der andere am IF gescheitert ist?

Bitte behandelt diese Frage sehr abstrakt, ich bin mir im Klaren, dass es aufgrund von Latenz usw. surreal ist, eine Abfrage zur selben Zeit an den Server zu senden. Irgendwo hatte ich mal gelesen, dass eine Tabelle immer in dem Moment für andere Zugriffe blockiert ist, wenn eine Abfrage stattfindet. Ich möchte daher wissen wie es sich verhält, wenn das Script 2 Mal zur selben Zeit aufgerufen wird :)

Herzlichen Dank schon mal für eure Antworten.
 
Meine Frage lautet: ist es theoretisch möglich, dass beide Inserts erfolgreich ausgeführt werden wenn das Script sozusagen an beiden Orten in der selben Nanosekunde aufgerufen wird, oder werden die SQL-Querys vom Server willkürlich in einer bestimmten Reihenfolge ausgeführt, so dass am Ende nur ein Query ausgeführt wird, weil der andere am IF gescheitert ist?

Kurze Antwort: Ja, das ist möglich.
Dafür gibt es allerdings Transaktionen.
 
Okay, ich habe mich in die Sache noch etwas reingelesen. Für meinen Fall wäre LOCK TABLES ausreichend, allerdings frage ich mich immer noch, wie die Datenbank entscheidet welcher Query Vorrang erhält und welcher eben als zweites ausgeführt wird. Nicht dass es wichtig wäre, weil in meinem Beispiel sowieso beide gleich sind.. :wink: Aber würde mich interessieren wie das technisch gelöst ist.
 
Das wird anhand der Prozess-Queue gelöst. Es können niemals beide Prozesse an der gleichen Stelle in der Queue stehen. Jener, der also zuerst Rechenzeit bekommt um in der Queue zu landen, wird vorrangig behandelt.
 
Okay, das klingt logisch. Ich werde das vllt. mal testen, indem ich meinem PHP-Script ein sleep() gebe und in der Zeit eine andere Abfrage starte :)

Gerade ist mir eingefallen, dass es evtl. im Beispiel auch zielführend wäre, der Spalte "wert" einen Unique-Index zu geben. Ist halt die Frage was passiert, wenn in diesem Fall beide Abfragen gleichzeitig beim Server ankommen. Um mal dein Stichwort "Rechenzeit" aufzugreifen: da würde dann ein Query bevorteilt werden und das Problem hätte sich durch den Unique erledigt (?)
 
Um mal dein Stichwort "Rechenzeit" aufzugreifen: da würde dann ein Query bevorteilt werden und das Problem hätte sich durch den Unique erledigt (?)

Ja, genau so. Allerdings solltest du dann auch noch eine auto_increment setzen, weil unique nicht automatisch aufsteigend bedeuten muss. Das als zweites ausgeführte Query könnte also bei einem unique ohne auto_increment auch kleiner sein als das erste, wodurch die Reihenfolge nicht mehr erkennbar wäre.
 
Bei einer Transaktion werden die Queries unterbrechungsfrei ausgeführt, die innerhalb der Transaktion sind
Nur logisch, aber nicht wirklich. Das Ergebnis sieht aus, als wären sie serialisiert worden, tatsächlich laufen sie aber (soweit möglich) parallel ab.
 
Danke für eure umfassende Hilfe, ich werde wohl direkt die Transaktionen von MySQL nutzen:

PHP:
mysql_query('SET autocommit=0;');
mysql_query('START TRANSACTION;');
mysql_query('LOCK TABLES test WRITE;');

// query [...]

mysql_query('COMMIT;');
mysql_query('UNLOCK TABLES;');

Funktioniert erstaunlich gut, allerdings muss man vorher der Tabelle den Typ "InnoDB" geben. Wenn ich jetzt noch der Spalte "wert" einen Unique-Index gebe, dürfte ich vor der benannten doppelten Ausführung sicher sein :)
 
Zuletzt bearbeitet:
Bedenke, dass du mit einem LOCK TABLES parallele Schreibzugriffe auf die Tabelle komplett unterbindest. Wenn (parallele) Performance eine Rolle spielt, ist das eine schlechte Wahl.
 
wobei man sich auch eine "Sperrtabelle" machen könnte.
Wenn man nun von 2 Prozessen ausgeht, die gleichzeitig gestartet werden und deren Logik so aussieht:
Code:
Originale Speichertabelle
| id | wert  |
|----|-------|
| 1  | alpha |
| 2  | beta  |
| 3  | gamma |

Sperrtabelle
| id |
|----|
| 4  |

dann könnte man mit der Logik: höchste ID = {höchste ID aus origTab UND Sperrtab} dafür sorgen, dass nie 2 Prozesse auf dieselbe ID schreiben.
Natürlich muss der Eintrag in der SperrTab ein COMMIT bekommen, und man muss hinterher die SperrTab wieder aufräumen.
 
Wenn so wieso beide Prozesse das gleiche schreiben kann man auch mit REPLACE INTO arbeiten.

Gesendet von meinem HTC Desire mit Tapatalk
 
Bitte behandelt diese Frage sehr abstrakt, ich bin mir im Klaren, dass es aufgrund von Latenz usw. surreal ist, eine Abfrage zur selben Zeit an den Server zu senden.
So abstrakt und unwahrscheinlich ist das gar nicht. Z.B. bei Facebook mit mehreren zehn- oder hunderttausend Datenbank-Updates pro Minute käme ein paralleles Schreiben in die selbe Tabelle je nach Datenmodell andauernd vor, wenn nicht bestimmte Maßnahmen (z.B. Transaktionen) davor schützen würden. Oracle nennt die Menge der Eigenschaften, die einen solchen Schutz gewährleisten, übrigens ACID.
Über ein PHP Script wird an 2 voneinander unabhängigen Orten der Letzte Datensatz abgefragt (wert = gamma).
Dann sollte diese Abfrage transaktional erfolgen, damit es zu keinen Dateninkonsistenzen kommt. Wie bitmuncher bereits beschrieben hat, können multiple Abfragen in eine Queue gestellt werden. Hierbei handelt es sich um eine lineare Datenstruktur nach dem FIFO-Prinzip. Die Queue kann als eindimensionaler Vektor verstanden werden, dessen Elemente in definierter Reihenfolge abgearbeitet werden. Die formale Definition der Queue lässt kein simultanes Abarbeiten von zwei Aufträgen zu (genau genommen soll sie genau so etwas verhindern): Queue
 
Zurück
Oben