Primärschlüssel

Primärschlüssel

am 04.01.2006 03:33:29 von Oliver Benning

Hallo,

normalerweise lasse ich mir den Primärschlüssel per autoincrement
erstellen. Jetzt reicht mir ein einfaches +1 aber nicht aus und ich muß
entweder den Wert auf Anwendungsebene berechnen und per
MySQL-Table-Locks absichern, oder ich verwende ein INSERT SELECT.

Ich wäge gerade ab, welchen der beiden Wege ich verwende.

1. Kann ich ein Table-Lock so setzen, daß der aktuelle Prozess lesen und
schreiben darf, die anderen aber nur lesen? Wenn ich das richtig
verstanden habe, ist READ für alle Nur-Lesen, auch für den Prozess, der
das Table-Lock ausführt und WRITE sperrt auch den Lesezugriff für die
anderen und die sind somit komplett blockiert.

2. Kann ich INSERT SELECT auch mit Werten von der Anwendungsebene
mischen, die noch in keiner anderen Tabelle existieren (VALUES(...))?

3. Wenn ich den Primärschlüssel (kein auto-increment) per INSERT SELECT
einfüge, wie erfährt dann die Anwendung, welcher Wert berechnet und
eingefügt wurde?


Gruß,
Oliver

Re: Primärschlüssel

am 04.01.2006 06:04:07 von Johannes Vogel

Hi Oliver

Oliver Benning wrote:
> normalerweise lasse ich mir den Primärschlüssel per autoincrement
> erstellen. Jetzt reicht mir ein einfaches +1 aber nicht aus und ich muß
> entweder den Wert auf Anwendungsebene berechnen und per
> MySQL-Table-Locks absichern, oder ich verwende ein INSERT SELECT.

Weshalb reicht ein +1 denn nicht aus?

> Ich wäge gerade ab, welchen der beiden Wege ich verwende.
> 1. Kann ich ein Table-Lock so setzen, daß der aktuelle Prozess lesen und
> schreiben darf, die anderen aber nur lesen? Wenn ich das richtig
> verstanden habe, ist READ für alle Nur-Lesen, auch für den Prozess, der
> das Table-Lock ausführt und WRITE sperrt auch den Lesezugriff für die
> anderen und die sind somit komplett blockiert.

Weshalb probierst du's nicht einfach kurz aus? Das hab ich gemacht, und
tatsächlich ist der Lesezugriff gesperrt während des WRITE-Locks.

> 2. Kann ich INSERT SELECT auch mit Werten von der Anwendungsebene
> mischen, die noch in keiner anderen Tabelle existieren (VALUES(...))?

Du kannst konstante Werte mit ins Select-Statement einbauen:
insert ... select 12, field1, field2 from tabelle where...

> 3. Wenn ich den Primärschlüssel (kein auto-increment) per INSERT SELECT
> einfüge, wie erfährt dann die Anwendung, welcher Wert berechnet und
> eingefügt wurde?

Bspw. durch ein erneutes Select. Aber wenn du's sowieso auf
Anwendungsebene errechnest, weisst du den Inhalt ja schon.

HTH, Johannes

Re: Primärschlüssel

am 04.01.2006 10:11:24 von Christian Kirsch

Oliver Benning schrieb:
> Hallo,
>
> normalerweise lasse ich mir den Primärschlüssel per autoincrement
> erstellen. Jetzt reicht mir ein einfaches +1 aber nicht aus und ich muß
> entweder den Wert auf Anwendungsebene berechnen und per
> MySQL-Table-Locks absichern, oder ich verwende ein INSERT SELECT.
>

Das liest sich so, als ob Du Semantik, d.h. Bedeutung, im
Primärschlüssel unterbringen wolltest. Und nun musst Du natürlich die
üblichen Race-Conditions vermeiden.

Wozu? Warum führst Du nicht eine zweite Spalte ein, die den von Dir
berechneten Wert enthält, und lässt den Primärschlüssel, wie er ist?

Re: Primärschlüssel

am 04.01.2006 10:34:59 von Axel Schwenke

"Oliver Benning" wrote:

> normalerweise lasse ich mir den Primärschlüssel per autoincrement
> erstellen. Jetzt reicht mir ein einfaches +1 aber nicht aus und ich muß
> entweder den Wert auf Anwendungsebene berechnen und per
> MySQL-Table-Locks absichern

Wieso das denn? Ein INSERT ist eine atomare Aktion. Mach also einfach
aus der Anwendung dein INSERT und teste das Ergebnis. Wenn ein
'duplicate key' Fehler zurückkommt, war der PK wohl schon vergeben.

> oder ich verwende ein INSERT SELECT.

Was meinst du damit? So was?
INSERT INTO tbl1 (id) SELECT MAX(id)+1 FROM tbl2

> 1. Kann ich ein Table-Lock so setzen, daß der aktuelle Prozess lesen und
> schreiben darf, die anderen aber nur lesen?

Ja. Das wäre dann ein READ LOCK.

> Wenn ich das richtig
> verstanden habe, ist READ für alle Nur-Lesen, auch für den Prozess, der
> das Table-Lock ausführt

Das verstehst du falsch. Das LOCK gilt für alle Clients *außer* dem der
das LOCK gesetzt hat. Anders wäre das auch sinnlos.

> 2. Kann ich INSERT SELECT auch mit Werten von der Anwendungsebene
> mischen, die noch in keiner anderen Tabelle existieren (VALUES(...))?

Klar. Z.B. so:
INSERT INTO foo (bla, blubb) SELECT laber, 'fasel' FROM bar

Hier kommt ein Wert aus der `laber` Spalte der Tabelle `bar`, der
andere Wert ist das String-Literal 'fasel'.

> 3. Wenn ich den Primärschlüssel (kein auto-increment) per INSERT SELECT
> einfüge, wie erfährt dann die Anwendung, welcher Wert berechnet und
> eingefügt wurde?

Du kannst den erzeugten PK in einer User-Variablen [1] speichern. Und
wenn es ein INT ist, kannst du auch LAST_INSERT_ID(neue_id) benutzen
um den Wert zu merken und dann LAST_INSERT_ID() um ihn auszulesen.

[1] http://dev.mysql.com/doc/refman/en/variables.html


XL

Re: Primärschlüssel

am 04.01.2006 11:09:16 von Oliver Benning

Johannes Vogel wrote:
>
> Oliver Benning wrote:
>> normalerweise lasse ich mir den Primärschlüssel per autoincrement
>> erstellen. Jetzt reicht mir ein einfaches +1 aber nicht aus und ich
>> muß entweder den Wert auf Anwendungsebene berechnen und per
>> MySQL-Table-Locks absichern, oder ich verwende ein INSERT SELECT.
>
> Weshalb reicht ein +1 denn nicht aus?

Ich benötige wilde Nummern, die nicht fortlaufend sind.

>> 3. Wenn ich den Primärschlüssel (kein auto-increment) per INSERT
>> SELECT einfüge, wie erfährt dann die Anwendung, welcher Wert
>> berechnet und eingefügt wurde?
>
> Bspw. durch ein erneutes Select. Aber wenn du's sowieso auf
> Anwendungsebene errechnest, weisst du den Inhalt ja schon.

Auf Anwendungsebene würde ich es berechnen mit den Table-Locks, aber das
komplette Blockieren aller anderen Prozesse gefällt mir nicht.

Wenn ich den Primärschlüssel aber innerhalb einer INSERT SELECT
Anweisung berechne, dann reicht nicht ein erneutes SELECT, weil alles,
bis auf den Primärschlüssel u.U. doppelt vorkommen kann uns sich dann
mehrere Anwendungsprozesse um denselben Datensatz streiten würden.

Re: Primärschlüssel

am 04.01.2006 11:32:56 von Oliver Benning

Axel Schwenke wrote:
> "Oliver Benning" wrote:
>
>> normalerweise lasse ich mir den Primärschlüssel per autoincrement
>> erstellen. Jetzt reicht mir ein einfaches +1 aber nicht aus und ich
>> muß entweder den Wert auf Anwendungsebene berechnen und per
>> MySQL-Table-Locks absichern
>
> Wieso das denn? Ein INSERT ist eine atomare Aktion. Mach also einfach
> aus der Anwendung dein INSERT und teste das Ergebnis. Wenn ein
> 'duplicate key' Fehler zurückkommt, war der PK wohl schon vergeben.
>
>> oder ich verwende ein INSERT SELECT.
>
> Was meinst du damit? So was?
> INSERT INTO tbl1 (id) SELECT MAX(id)+1 FROM tbl2

Genau, weiss jemand, ob zwischen SELECT und INSERT noch andere Befehle
von anderen Prozessen eingefügt werden können, oder ist garantiert, daß
ich bei dem von Dir genannten Statement auch auf jeden Fall keinen
Duplikate-Key Fehler bekomme?

>> 1. Kann ich ein Table-Lock so setzen, daß der aktuelle Prozess lesen
>> und schreiben darf, die anderen aber nur lesen?
>
> Ja. Das wäre dann ein READ LOCK.
>
>> Wenn ich das richtig
>> verstanden habe, ist READ für alle Nur-Lesen, auch für den Prozess,
>> der das Table-Lock ausführt
>
> Das verstehst du falsch. Das LOCK gilt für alle Clients *außer* dem
> der das LOCK gesetzt hat. Anders wäre das auch sinnlos.

In der MySQL Doku steht aber :

"If a thread obtains a READ lock on a table, that thread (and all other
threads) can only read from the table."

Was doch bedeutet, daß "that thread" auch nur Lesen und nicht Schreiben
kann.

>> 3. Wenn ich den Primärschlüssel (kein auto-increment) per INSERT
>> SELECT einfüge, wie erfährt dann die Anwendung, welcher Wert
>> berechnet und eingefügt wurde?
>
> Du kannst den erzeugten PK in einer User-Variablen [1] speichern. Und
> wenn es ein INT ist, kannst du auch LAST_INSERT_ID(neue_id) benutzen
> um den Wert zu merken und dann LAST_INSERT_ID() um ihn auszulesen.
>
> [1] http://dev.mysql.com/doc/refman/en/variables.html

Super, das habe ich gesucht.

Re: Re: Primärschlüssel

am 04.01.2006 13:02:04 von Axel Schwenke

"Oliver Benning" wrote:
> Axel Schwenke wrote:

>> INSERT INTO tbl1 (id) SELECT MAX(id)+1 FROM tbl2
>
> Genau, weiss jemand, ob zwischen SELECT und INSERT noch andere Befehle
> von anderen Prozessen eingefügt werden können, oder ist garantiert, daß
> ich bei dem von Dir genannten Statement auch auf jeden Fall keinen
> Duplikate-Key Fehler bekomme?

Das sind zwei verschiedene Dinge.

1. Ja, dieses Statement ist atomar. Es gibt keine race Konflikte.
2. Das hilft dir nicht automatisch, duplicate errors zu vermeiden.

(ich INSERTe und SELECTe oben aus verschiedenen Tabellen)

>>> 1. Kann ich ein Table-Lock so setzen, daß der aktuelle Prozess lesen
>>> und schreiben darf, die anderen aber nur lesen?
>>
>> Ja. Das wäre dann ein READ LOCK.

Ähm. Fehler vom Amt.
Ich ziehe meine Behauptung zurück und behaupte das Gegenteil. :-/

Bleiben dir nur "richtige" Transaktionen und SELECT ... FOR UPDATE.


XL

Re: Primärschlüssel

am 05.01.2006 02:16:36 von Oliver Benning

Oliver Benning wrote:
> normalerweise lasse ich mir den Primärschlüssel per autoincrement
> erstellen. Jetzt reicht mir ein einfaches +1 aber nicht aus und ich
> muß entweder den Wert auf Anwendungsebene berechnen und per
> MySQL-Table-Locks absichern, oder ich verwende ein INSERT SELECT.

Zusatzfrage, wie selektiere ich den zuletzt eingefügten Datensatz, wenn
es keine auto-increment Spalte gibt (für LAST_INSERT_ID), der
Primärschlüssel "zufällig" ist (es greift also keine max() Funktion) und
ein Timestamp u.U. bei mehreren kurz aufeinander eingefügten Datensätzen
gleich ist?

Re: Primärschlüssel

am 05.01.2006 10:02:22 von Dominik Echterbruch

Oliver Benning wrote:
> Oliver Benning wrote:
>
>> normalerweise lasse ich mir den Primärschlüssel per autoincrement
>> erstellen. Jetzt reicht mir ein einfaches +1 aber nicht aus und ich
>> muß entweder den Wert auf Anwendungsebene berechnen und per
>> MySQL-Table-Locks absichern, oder ich verwende ein INSERT SELECT.
>
>
> Zusatzfrage, wie selektiere ich den zuletzt eingefügten Datensatz, wenn
> es keine auto-increment Spalte gibt (für LAST_INSERT_ID), der
> Primärschlüssel "zufällig" ist (es greift also keine max() Funktion) und
> ein Timestamp u.U. bei mehreren kurz aufeinander eingefügten Datensätzen
> gleich ist?

Welches wäre denn dann deiner Meinung nach der letzte Datensatz? Wenn du
diese Frage eindeutig beantworten kannst, kann man das sicherlich auch
MySQL beibringen.


Grüße,
Dominik
--
MonstersGame - Die Schlacht zwischen Vampiren und Werwölfen
http://spielwelt6.monstersgame.net/?ac=vid&vid=3018786

Re: Primärschlüssel

am 05.01.2006 11:56:10 von Johannes Vogel

Hi Oliver

Oliver Benning wrote:
> Zusatzfrage, wie selektiere ich den zuletzt eingefügten Datensatz, wenn
> es keine auto-increment Spalte gibt (für LAST_INSERT_ID), der
> Primärschlüssel "zufällig" ist (es greift also keine max() Funktion) und
> ein Timestamp u.U. bei mehreren kurz aufeinander eingefügten Datensätzen
> gleich ist?

Genau deshalb ist dein Vorhaben blödsinn. Es gibt keinen Grund, nicht
einen fortlaufenden Primärschlüssel zu verwenden und daneben den
gewünschten zufälligen Code zu speichern.

OK, falls immer möglich, sollte man einen natürlichen Schlüssel
verwenden. Doch deine Zufallsnummer erscheint mir überhaupt nicht
natürlich...

HTH, Johannes

Re: Primärschlüssel

am 22.02.2006 20:51:43 von Thomas Rachel

Oliver Benning wrote:

>> Weshalb reicht ein +1 denn nicht aus?
>
> Ich benötige wilde Nummern, die nicht fortlaufend sind.

Dann nimm eine fortlaufende Nummer, und führe darauf dann

select conv(concat(substring(md5(num),1,8)),16,10);

aus.


HTH,

Thomas