Vous pouvez utiliser des LOCK pour rendre les choses SERIALIZABLE mais cela réduit la simultanéité. Pourquoi ne pas essayer d'abord la condition commune ("la plupart du temps insérer ou sélectionner la plupart du temps") suivie d'une gestion sûre de l'action "corrective" ? C'est-à-dire le modèle "JFDI"...
Principalement des INSERTS attendus (ball park 70-80 % +) :
Essayez simplement d'insérer. En cas d'échec, la ligne a déjà été créée. Pas besoin de vous soucier de la simultanéité car le TRY/CATCH traite les doublons pour vous.
BEGIN TRY
INSERT Table VALUES (@Value)
SELECT @id = SCOPE_IDENTITY()
END TRY
BEGIN CATCH
IF ERROR_NUMBER() <> 2627
RAISERROR etc
ELSE -- only error was a dupe insert so must already have a row to select
SELECT @id = RowID FROM Table WHERE RowValue = @VALUE
END CATCH
Principalement des SELECT :
Similaire, mais essayez d'abord d'obtenir des données. Aucune donnée =INSERT nécessaire. Encore une fois, si 2 appels simultanés tentent d'INSERER car ils ont tous deux trouvé la ligne manquant les poignées TRY/CATCH.
BEGIN TRY
SELECT @id = RowID FROM Table WHERE RowValue = @VALUE
IF @@ROWCOUNT = 0
BEGIN
INSERT Table VALUES (@Value)
SELECT @id = SCOPE_IDENTITY()
END
END TRY
BEGIN CATCH
IF ERROR_NUMBER() <> 2627
RAISERROR etc
ELSE
SELECT @id = RowID FROM Table WHERE RowValue = @VALUE
END CATCH
Le 2e semble se répéter, mais il est très concurrent. Les verrous permettraient d'obtenir le même résultat, mais au détriment de la concurrence...
Modifier :
Pourquoi pas utiliser FUSIONNER...
Si vous utilisez la clause OUTPUT, elle ne renverra que ce qui est mis à jour. Vous avez donc besoin d'un UPDATE factice pour générer la table INSERTED pour la clause OUTPUT. Si vous devez effectuer des mises à jour factices avec de nombreux appels (comme l'implique OP), il y a beaucoup d'écritures dans le journal juste pouvoir utiliser MERGE.