2009-04-11 8 views
0

Voici un extrait de ma base de données en cours (changé la table des noms pour une compréhension plus facile):Scoped/clés de substitution composites dans MySQL

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

id est toujours une clé de substitution, créé avec auto_increment.

Je souhaite que la clé de substitution Pet.id soit "délimitée" par Pet.ownerFK ou, en d'autres termes, ait une clé composée [ownerFk, id] comme clé minimale. Je veux que le tableau se comporter comme ceci:.

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) 

J'utilise actuellement ce feature of MyISAM où « vous pouvez spécifier AUTO_INCREMENT sur une colonne secondaire dans un index multiple de colonne Dans ce cas, la valeur générée pour la colonne AUTO_INCREMENT est calculé comme MAX(auto_increment_column) + 1 WHERE prefix=given-prefix Ceci est utile lorsque vous voulez mettre des données dans des groupes ordonnés. "

Cependant, en raison de diverses raisons (et peut-être évidentes), je veux passer de MyISAM à InnoDB, car j'ai besoin de transactions à certains endroits.

Est-il possible de réaliser cet effet avec InnoDB?

J'ai trouvé quelques messages sur ce problème, beaucoup d'entre eux ont proposé d'écrire-verrouiller la table avant l'insertion. Je ne suis pas très familier avec ceci, mais ne serais pas une table-écriture-verrouiller un peu d'une révision pour celui-ci? J'ai plutôt pensé à avoir des transactions en écriture sécurisée (ce que je n'ai jamais fait auparavant) si cela est possible - avoir un Owner.current_pet_counter comme champ d'assistance.

donc une autre solution acceptable serait ...

En fait, je ne l'ont pas besoin « scope » ID pour faire partie de la clé réelle. Ma conception de base de données utilise un tableau séparé "permalink" qui utilise cette "fonctionnalité". Je l'utilise actuellement comme une solution de contournement pour les transactions manquantes. Je pensais à l'alternative suivante:

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; 

Je n'ai pas travaillé encore avec des transactions/transactionvars dans MySQL, donc je ne sais pas s'il y aurait de sérieux problèmes avec celui-ci. Note: Je ne veux pas réutiliser id s qui ont été donnés à un animal de compagnie une fois. C'est pourquoi je n'utilise pas MAX(). Cette solution comporte-t-elle des réserves?

Répondre

1

Je ne crois pas. Si vous deviez vraiment avoir ce schéma, vous pourriez utiliser une transaction pour sélectionner MAX (id) WHERE ownerFK, puis INSERT.

Je suis très sceptique mais il y a une bonne raison pour ce schéma; la clé primaire est maintenant aussi un fait sur la clé, ce qui pourrait rendre les théoriciens de la base de données mécontents.

Normalement, vous voudriez que 'id' soit vraiment une clef primaire propre, avec ownerFK utilisé pour grouper et, si vous en aviez besoin, une colonne 'rank' séparée pour placer les familiers dans un ordre particulier par propriétaire , et un index UNIQUE sur (ownerFK, rang).

+0

Je vois ce que vous voulez dire. Ma conception de base de données réelle diffère un peu, et je n'ai pas besoin de faire partie de la clé primaire. J'ai mis à jour la question avec la solution actuelle que j'évalue. –

Questions connexes