Recht häufig benötigt man nach einer INSERT-Operation auf eine Tabelle mit einer automatisch inkrementierten ID als Primärschlüssel den durch diese Operation erzeugten Auto-Increment-Wert. Beispielsweise dafür, um anschließend weitere Operationen mit diesem Datensatz vorzunehmen oder die ID in anderen Tabellen als Fremdschlüssel zu verwenden. Zwei unterschiedliche Wege diese ID herauszufinden sollen in diesem Beitrag verglichen werden.
Denis hat vor einiger Zeit in den Themenvorschlägen vorgeschlagen, dieses Thema einmal näher zu untersuchen und dabei folgende zwei Wege vorgeschlagen.
1. Per SQL-Abfrage
Hierbei wird nach der INSERT-Query noch eine weitere Query an MySQL abgesendet, die einen Datensatz zurückgibt, der allein die ID enthält:
mysql_query("INSERT INTO tabelle (spalte1,spalte2,...) VALUES ('wert1','wert2',...)"); $rs = mysql_query("SELECT LAST_INSERT_ID()"); $id = mysql_result($rs,0); |
2. Per PHP
Eine andere Möglichkeit ist die Abfrage durch PHP erledigen zu lassen. Dies geschieht über den Befehl mysql_insert_id().
mysql_query("INSERT INTO tabelle (spalte1,spalte2,...) VALUES ('wert1','wert2',...)"); $id = mysql_insert_id(); |
Grundsätzlich erzeugen beide Varianten also gleiche Lösungen. Es fällt aber auf, dass man im Fall 1 zusätzlich noch das Result Set auslesen muss, um an den Wert zu gelangen.
Die Ergebnisse sehen aber folgendermaßen aus:
Datei | Gesamtlaufzeit | durchschnittliche Laufzeit pro Durchlauf | Verhältnis zur schnellsten Variante |
---|---|---|---|
result_mysql_insert_id.php | 6.168871 s | 6.169 ms | 100 % |
result_last_insert_id.php | 6.178885 s | 6.179 ms | 100 % |
Es ist zu erkennen, dass beide Varianten gleich schnell sind. Hinsichtlich der Performance gibt es also keine Unterschiede.
Die Gründe kann ich nicht 100%ig verifizieren, jedoch könnte ich mir vorstellen, dass mysql_insert_id() intern exakt die gleiche SQL-Abfrage ausführt und letzten Endes bei beiden Wegen exakt dasselbe getan wird.
Ich werde weiterhin mysql_insert_id() bevorzugen, weil man dafür einfach eine Zeile weniger benötigt, aber das sei jedem selbst überlassen. Wer nach Lines of Code bezahlt wird, sollte natürlich LAST_INSERT_ID() abfragen 😉
Die verwendeten Scripte und die Ergebnisse gibts natürlich zum Download.
Das war also mal ein Beitrag, der euch nicht dazu bringen wird, gleich alle Scripte zu überarbeiten. Ich hoffe aber trotzdem, dass er informativ ist und ihr euch zukünftig nicht mehr den Kopf zerbrechen müsst. 😉
Ist race-conditions-sicher?
Ja beide Varianten, da die Anfrage der letzten eingefügten ID stets für die aktuelle Verbindung gilt. Und da pro Seitenaufruf eine neue Verbindung geöffnet wird, ja. Wie es bei persistenten Verbindungen ist, weiß ich allerdings nicht (man könnte ja gleichzeitig 2 Browserfenster öffnen). Schätze aber, dass es auch dort sicher ist.
Persistente Verbindung werden ja auch jeweils nur von einem Prozess genutzt, dementsprechend sind die auch in sich sicher.
Persistente Verbindungen sollte man aber bei mysql eigentlich eh nicht verwenden… schafft bei falscher Konfiguration nur zusätzliche (schwerwiegende) Probleme (keine freie Connection mehr am DB-Server -> Prozess hat keinen Zugriff auf Datenbank, alle anderen Connections werden von anderen Prozessen belegt) und bringt bei MySQL relativ wenig bis gar nichts, weil der Verbindungsaufbau billig ist.
ach dann is ja gut das man nicht direkt alle seine scripte wieder umschreiben muss 😉
also schön sicher zu sein das sein bisheriges werk ok is XD
Wichtig zu wissen ist, ob LAST_INSERT_ID nur für mysql existiert oder womöglich auf jeder Plattform…
Somit wäre der Vorteil beim ableiten von Klassen, lediglich eine Funktion und nicht für fast jede Plattform eine andere Funktion abgreifen…
Somit wäre bei LAST_INSERT_ID weniger aufwand vorhanden…
(falls man von aufwand sprechen kann)…
Ah, gut zu wissen, dass das threadsafe ist. Ich hatte da immer meine Bedenken und gemieden, aber auch noch keinen Fall bei dem ich sofort die ID gebraucht hätte 🙂
@sabre
Je komplexer deine Scripte um so höher die Wahrscheinlichkeit, das ein anderes query auf die db zugreift, bevor Du die id hast. Deshalb ist es imho sicherer sich anzugewöhnen die last_insert_id direkt nach dem INSERT abzufischen und gegebenenfalls als Variable oder Konstante weiterzureichen.
Auch wenn es spät kommt:
Wichtig zu erwähnen ist, dass „mysql_insert_id()“ nur funktioniert, wenn der MySQL-Typ des PK-Feldes nicht vom Typ BIGINT ist.
In diesem Falle sollte die MySQL-Interne Funktion (siehe im Blog) verwendet werden.
Diese Warnung findet sich auch in der PHP-Manual zu dieser Funktion:
http://de2.php.net/manual/en/function.mysql-insert-id.php
Wenn man den Nächsten Indexwert haben möchte kann man folgenden Befehl verwenden.
SHOW TABLE STATUS FROM `database` LIKE ‚table‘
das ganze mit fetch_row oder array auswerten und in Zeile 10 steht der nächste Indexwert.
SHOW TABLE STATUS ist nicht transaktionssicher!