2009-04-11 6 views
0

Hier ein Auszug aus meiner aktuellen Datenbank ist (geändert, um die Tabellennamen für ein leichteres Verständnis):Scoped/Composite Ersatzschlüssel in MySQL

Pet(ownerFK, id, name, age) 
Owner(id, name) 

Wo id ist immer ein Ersatzschlüssel, mit auto_increment erstellt.

Ich mag, dass der Ersatzschlüssel Pet.id habe „scoped“ von Pet.ownerFK oder in anderen Worten werden, habe eine zusammengesetzten Schlüssel [ownerFk, id] als meinen minimalen Schlüssel. Ich möchte die Tabelle wie folgt verhalten:.

INSERT Pet(1, ?, "Garfield", 8); 
INSERT Pet(1, ?, "Pluto", 12); 
INSERT Pet(2, ?, "Mortimer", 1); 

SELECT * FROM Pet; 
    RESULT: 
    Pet(1, 1, "Garfield", 8) 
    Pet(1, 2, "Pluto", 12) 
    Pet(2, 1, "Mortimer", 1) 

Ich bin derzeit mit diesen feature of MyISAM wo „Sie AUTO_INCREMENT auf einer sekundären Spalte in einem mehrspaltigen Index In diesem Fall wird der erzeugte Wert für die AUTO_INCREMENT Spalte angeben wird als MAX(auto_increment_column) + 1 WHERE prefix=given-prefix berechnet. Dies ist nützlich, wenn Sie Daten in geordnete Gruppen einfügen möchten. "

Aufgrund verschiedener (und vielleicht offensichtlicher) Gründe möchte ich von MyISAM zu InnoDB wechseln, da ich an manchen Stellen Transaktionen benötige.

Gibt es einen Weg, wie man diesen Effekt mit InnoDB erreichen kann?

Ich habe einige Beiträge zu diesem Problem gefunden, viele von ihnen vorgeschlagen, die Tabelle vor dem Einfügen zu sperren. Ich bin nicht sehr damit vertraut, aber wäre nicht ein Tisch-Schreib-Schloss ein bisschen eine Überholung für diesen einen? Ich dachte eher an schreibsichere Transaktionen (was ich vorher noch nie gemacht habe), wenn diese möglich sind - mit einem Owner.current_pet_counter als Hilfsfeld.

So eine andere akzeptable Lösung wäre ...

Eigentlich brauche ich nicht die „scoped“ ID Teil des eigentlichen Schlüssel zu sein. Mein aktuelles Datenbankdesign verwendet eine separate "Permalink" -Tabelle, die diese "Funktion" verwendet. Ich verwende es derzeit als Workaround für die fehlenden Transaktionen. Ich dachte an die folgende Alternative:

Pet(id, ownerFK, scopedId, name, age), KEY(id), UNIQUE(ownerFK, scopedId) 
Owner(id, name, current_pet_counter) 

START TRANSACTION WITH CONSISTENT SNAPSHOT; 
SELECT @new=current_pet_counter FROM Owner WHERE id = :owner_id; 
INSERT Pet(?, :owner_id, @new, "Pluto", 21); 
UPDATE Owners SET current_pet_counter = @new + 1 WHERE id = :owner_id; 
COMMIT; 

Ich habe nicht mit Transaktionen/transactionvars in MySQL noch gearbeitet, so dass ich weiß nicht, ob es mit dieser ernsten Probleme wäre. Hinweis: Ich möchte nicht id s, die einmal an ein Haustier gegeben wurden, wiederverwenden. Deshalb verwende ich nicht MAX(). Hat diese Lösung irgendwelche Vorbehalte?

Antwort

1

Ich glaube nicht. Wenn Sie wirklich dieses Schema haben müssten, könnten Sie eine Transaktion verwenden, um MAX (id) WHERE eignerFK und dann EINFÜGEN auszuwählen.

Ich bin sehr skeptisch, es gibt jedoch einen guten Grund für dieses Schema; der Primärschlüssel ist jetzt auch eine Tatsache über den Schlüssel, der die Database-Theoretiker unglücklich machen könnte.

Normalerweise möchten Sie, dass 'id' wirklich ein eigener primärer Schlüssel ist, mit eignerFK zum Gruppieren und, wenn Sie es brauchen, einer separaten 'Rang'-Spalte, um Haustiere in eine bestimmte Reihenfolge pro Besitzer zu setzen und ein eindeutiger Index über (eignerFK, Rang).

+0

Ich sehe Ihren Standpunkt. Mein tatsächlicher Datenbankentwurf unterscheidet sich ein wenig und ich brauche ihn auch nicht als Teil des Primärschlüssels. Ich habe die Frage mit der aktuellen Lösung, die ich evaluiere, aktualisiert. –