本文介紹了SQL Server中Upsert的三種常見寫法以及他們的性能比較。
SQL Server並不支持原生的Upsert語句,通常使用組合語句實現upsert功能。
假設有表table_A,各字段如下所示:
int型Id為主鍵。
方法1:先查詢,根據查詢結果判斷使用insert或者update
IF EXISTS (SELECT 1 FROM table_A WHERE Id = @Id) BEGIN UPDATE dbo.table_A SET Value = @Value WHERE Id = @Id; END ELSE BEGIN INSERT INTO dbo.table_A (Id, Value) VALUES(@Id, @Value) END
方法2:先更新,根據更新結果影響的條目數判斷是否需要插入
UPDATE dbo.table_A SET Value = @Value WHERE Id = @Id; IF(@@ROWCOUNT = 0) BEGIN INSERT INTO dbo.table_A (Id, Value) VALUES(@Id, @Value) END
方法3:使用MERGE語句,將待upsert的數據作為source,merge到目標表
MERGE INTO table_A as T USING (SELECT @Id AS id, @Value AS value ) AS S ON T.Id = S.id WHEN MATCHED THEN UPDATE SET T.Value = S.value WHEN NOT MATCHED THEN INSERT(Id, Value) VALUES(S.id, S.value);
性能比較
在50萬行數據項中隨機upsert10萬次
場景一:upsert數據項100%命中update
場景二:upsert數據項100%命中insert
場景三:upsert數據項Id為隨機數,~50%insert,~50%update
從圖中可以看出實驗數據存在部分偏差,大體上這三種方法在性能上的差別非常小。對於絕大多數upsert並非關鍵路徑的程序,方法2在可讀性和執行性能上綜合來講是較優的方案。
在對性能苛求的場景,可以選用MERGE語句,以下是MERGE語句的優點:”
- Faster performance. The Engine needs to parse, compile, and execute only one query instead of three (and no temporary variable to hold the key).
- Neater and simpler T-SQL code (after you get proficient in MERGE).
- No need for explicit BEGIN TRANSACTION/COMMIT. MERGE is a single statement and is executed in one implicit transaction.
- Greater functionality. MERGE can delete rows that are not matched by source (SRC table above). For example, we can delete row 1 from A_Table because its Data column does not match Search_Col in the SRC table. There is also a way to return inserted/deleted values using the OUTPUT clause.“
引用:http://www.sergeyv.com/blog/archive/2010/09/10/sql-server-upsert-equivalent.aspx