Il existe quelques scénarios possibles qui sont faciles à résoudre et un autre pernicieux qui ne l'est pas.
Pour un utilisateur qui entre une valeur, puis saisit la même valeur quelque temps plus tard, un simple SELECT avant que INSERT détecte le problème. Cela fonctionne dans le cas où un utilisateur soumet une valeur et quelque temps plus tard, un autre utilisateur soumet la même valeur.
Si l'utilisateur soumet une liste de valeurs avec des doublons - disons {ABC, DEF, ABC} - en une seule invocation du code, l'application peut détecter et filtrer les doublons, provoquant peut-être une erreur. Vous devrez également vérifier que la base de données ne contient aucune des valeurs uniques avant l'insertion.
Le scénario délicat est lorsque l'écriture d'un utilisateur se trouve à l'intérieur du SGBD en même temps que l'écriture d'un autre utilisateur et qu'il écrit la même valeur. Ensuite, vous avez une course une condition entre eux. Étant donné que le SGBD est (très probablement - vous ne dites pas lequel vous utilisez) un système multitâche préemptif, toute tâche peut être interrompue à tout moment de son exécution. Cela signifie que la tâche de l'utilisateur1 peut vérifier qu'il n'y a pas de ligne existante, puis la tâche de l'utilisateur2 peut vérifier qu'il n'y a pas de ligne existante, puis la tâche de l'utilisateur1 peut insérer cette ligne, puis la tâche de l'utilisateur2 peut insérer cette ligne. À chaque point, les tâches sont individuellement satisfaites de faire la bonne chose. Globalement, cependant, une erreur se produit.
Habituellement, un SGBD gérerait cela en mettant un verrou sur la valeur en question. Dans ce problème, vous créez une nouvelle ligne, il n'y a donc rien à verrouiller. La réponse est un verrou de plage. Comme il le suggère, cela verrouille une plage de valeurs, qu'elles existent actuellement ou non. Une fois verrouillée, cette plage ne peut plus être accédée par une autre tâche tant que le verrou n'est pas libéré. Pour obtenir des verrous de plage, vous devez spécifier et le niveau d'isolement de SERIALIZABLE . Le phénomène d'une autre tâche se faufilant après une vérification de votre tâche est connu sous le nom d' enregistrements fantômes .
La définition du niveau d'isolement sur Sérialisable dans l'ensemble de l'application aura des implications. Le débit sera réduit. D'autres conditions de course qui fonctionnaient assez bien dans le passé peuvent commencer à montrer des erreurs maintenant. Je suggère de le définir sur la connexion qui exécute votre code induisant des doublons et de laisser le reste de l'application tel quel.
Une alternative basée sur le code consiste à vérifier après l'écriture plutôt qu'avant. Faites donc l'INSERT, puis comptez le nombre de lignes qui ont cette valeur de hachage. S'il y a des doublons, annulez l'action. Cela peut avoir des résultats pervers. Dites que la tâche 1 écrit puis la tâche 2. Ensuite, la tâche 1 vérifie et trouve un doublon. Il recule même s'il était le premier. De même, les deux tâches peuvent détecter le doublon et les deux annulations. Mais au moins, vous aurez un message à utiliser, un mécanisme de nouvelle tentative et aucun nouveau doublon. Les annulations sont désapprouvées, tout comme l'utilisation d'exceptions pour contrôler le flux du programme. Notez bien que tousle travail dans la transaction sera annulé, pas seulement l'écriture induisant un doublon. Et vous devrez avoir des transactions explicites qui peuvent réduire la concurrence. La vérification en double sera horriblement lente, sauf si vous avez un index sur le hachage. Si vous le faites, vous pouvez tout aussi bien en faire un modèle unique!
Comme vous l'avez commenté, la vraie solution est un index unique. Il me semble que cela devrait s'intégrer dans votre fenêtre de maintenance (bien que vous connaissiez bien votre système). Disons que le hachage fait huit octets. Pour cent millions de lignes, c'est environ 1 Go. L'expérience suggère qu'un peu de matériel raisonnable traiterait ces nombreuses lignes en une ou deux minutes. La vérification et l'élimination des doublons ajouteront à cela, mais peuvent être scriptées à l'avance. Ce n'est qu'un aparté, cependant.