Mnoho lidí vám navrhne, abyste použili MERGE
, ale varuji vás před tím. Ve výchozím nastavení vás nechrání před souběžnými a rasovými podmínkami o nic víc než několik příkazů, ale přináší další nebezpečí:
- Používejte opatrně s příkazem MERGE serveru SQL Server
- Čemu se vyvarovat, pokud chcete použít MERGE
- Vzory a antivzory UPSERT serveru SQL Server
I když je k dispozici tato "jednodušší" syntaxe, stále preferuji tento přístup (pro stručnost vynecháno zpracování chyb):
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;
Více informací o tomto UPSERT
přístup zde:
- Přestaňte prosím používat tento anti-vzor UPSERT
Mnoho lidí navrhne tento způsob:
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;
To vše však zajišťuje, že budete možná muset přečíst tabulku dvakrát, abyste našli řádek (řádky), které mají být aktualizovány. V prvním příkladu budete potřebovat najít řádek(y) pouze jednou. (V obou případech, pokud nejsou nalezeny žádné řádky z počátečního čtení, dojde k vložení.)
Ostatní navrhnou tento způsob:
BEGIN TRY
INSERT ...
END TRY
BEGIN CATCH
IF ERROR_NUMBER() = 2627
UPDATE ...
END CATCH
To je však problematické, pokud z žádného jiného důvodu, než že ponechání SQL Serveru zachytit výjimky, kterým jste mohli předejít, je mnohem dražší, s výjimkou výjimečného scénáře, kdy selže téměř každý insert. Dokazuji to zde:
- Před vstupem do TRY/CATCH zkontrolujte potenciální porušení omezení
- Vliv různých technik zpracování chyb na výkon
Nejste si jisti, co si myslíte, že získáte jediným prohlášením; Myslím, že tím nic nezískáš. MERGE
je jediný příkaz, ale stejně musí skutečně provádět více operací – i když si myslíte, že tomu tak není.