U kunt LOCKs gebruiken om dingen SERIALISABLE te maken, maar dit vermindert gelijktijdigheid. Waarom probeert u niet eerst de algemene voorwaarde ("meestal invoegen of meestal selecteren"), gevolgd door een veilige afhandeling van de "herstelactie"? Dat wil zeggen, het "JFDI"-patroon...
Meestal INSERT's verwacht (ballenpark 70-80%+):
Probeer maar eens in te voegen. Als het mislukt, is de rij al gemaakt. U hoeft zich geen zorgen te maken over gelijktijdigheid, want de TRY/CATCH behandelt duplicaten voor u.
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
Meestal SELECTEERT:
Vergelijkbaar, maar probeer eerst gegevens te krijgen. Geen gegevens =INSERT nodig. Nogmaals, als 2 gelijktijdige oproepen proberen te INSERT omdat ze allebei ontdekten dat de rij de TRY/CATCH-handles mist.
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
De 2e lijkt zich te herhalen, maar is zeer gelijktijdig. Sloten zouden hetzelfde bereiken, maar ten koste van gelijktijdigheid...
Bewerken:
Waarom niet om SAMENVOEGEN te gebruiken...
Als u de OUTPUT-clausule gebruikt, wordt alleen geretourneerd wat is bijgewerkt. U hebt dus een dummy-UPDATE nodig om de INSERTED-tabel voor de OUTPUT-component te genereren. Als je dummy-updates moet doen met veel oproepen (zoals geïmpliceerd door OP), zijn dat veel log-schrijfacties slechts om MERGE te kunnen gebruiken.