Wiele osób zasugeruje użycie MERGE
, ale ostrzegam przed tym. Domyślnie nie chroni Cię przed współbieżnością i warunkami wyścigu bardziej niż wieloma oświadczeniami, ale wprowadza inne zagrożenia:
- Zachowaj ostrożność z instrukcją MERGE SQL Server
- Czego unikać, jeśli chcesz korzystać z funkcji MERGE
- Wzorce i antywzorce SQL Server UPSERT
Nawet przy dostępnej „prostszej” składni nadal wolę to podejście (obsługa błędów pominięta dla zwięzłości):
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
UPDATE dbo.table SET ... WHERE PK = @PK;
IF @@ROWCOUNT = 0
BEGIN
INSERT dbo.table(PK, ...) SELECT @PK, ...;
END
COMMIT TRANSACTION;
Więcej informacji na temat tego UPSERT
podejście tutaj:
- Proszę przestać używać tego antywzorca UPSERT
Wiele osób zasugeruje w ten sposób:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
IF EXISTS (SELECT 1 FROM dbo.table WHERE PK = @PK)
BEGIN
UPDATE ...
END
ELSE
BEGIN
INSERT ...
END
COMMIT TRANSACTION;
Ale wszystko to zapewnia, że może być konieczne dwukrotne przeczytanie tabeli, aby zlokalizować wiersze, które mają zostać zaktualizowane. W pierwszym przykładzie wystarczy raz zlokalizować wiersze. (W obu przypadkach, jeśli nie zostaną znalezione żadne wiersze z początkowego odczytu, nastąpi wstawienie).
Inni zasugerują w ten sposób:
BEGIN TRY
INSERT ...
END TRY
BEGIN CATCH
IF ERROR_NUMBER() = 2627
UPDATE ...
END CATCH
Jest to jednak problematyczne, jeśli nie z innego powodu niż umożliwienie SQL Serverowi przechwytywania wyjątków, którym można było zapobiec w pierwszej kolejności, jest znacznie droższe, z wyjątkiem rzadkiego scenariusza, w którym prawie każde wstawienie kończy się niepowodzeniem. Udowadniam to tutaj:
- Sprawdzanie potencjalnych naruszeń ograniczeń przed wejściem TRY/CATCH
- Wpływ na wydajność różnych technik obsługi błędów
Nie jesteś pewien, co Twoim zdaniem zyskasz dzięki pojedynczemu oświadczeniu; Myślę, że nic nie zyskasz. MERGE
jest pojedynczą instrukcją, ale i tak naprawdę musi wykonać wiele operacji - nawet jeśli sprawia, że myślisz, że tak nie jest.