将数据插入/更新到数据库的最佳方法是什么

时间:2015-09-29 06:18:15

标签: c# sql database performance

鉴于我们有以下表格:

CREATE TABLE TestData 
(
    ID INT NOT NULL PRIMARY KEY,
    Value INT
)

在向表中写入数据时,如果ID已存在,我将尝试UPDATE表,或者INSERT新行。

我在生产代码中编写或遇到过几个选项:

  1. 首先执行UPDATE查询,如果没有更新行,请执行INSERT查询

  2. 首先执行Insert查询,如果失败,请执行INSERT查询

  3. 首先使用新ID执行SELECT查询,如果该行存在,请执行UPDATE其他INSERT查询

  4. 执行一个大查询以执行所有选择更新或插入

  5. 我的问题是上述选项(或您自己的方法)中的best practicemost efficientpreferred method是什么?

    以上选项的示例代码:

    (1)首先执行UPDATE查询,如果没有更新行,请执行INSERT查询

    int affectedRows = 0;
    using (IDbCommand updateCmd = new SqlCommand("UPDATE TestData SET Value = @Value WHERE ID = @ID", myConn))
    {
        try
        {
            // ...add params
            affectedRows = updateCmd.ExecuteNonQuery();
        }
        catch (SqlException) { /*...*/ }
    }
    
    if (affectedRows == 0)
    {
        using (IDbCommand insertCmd = new SqlCommand("INSERT INTO TestData VALUES (@ID, @Value)", myConn))
        {
            try
            {
                // ...add params
                affectedRows = insertCmd.ExecuteNonQuery();
            }
            catch (SqlException) { /*...*/ }
        }
    }  
    

    (2)首先执行Insert查询,如果失败,则执行INSERT查询

    int affectedRows = 0;
    using (IDbCommand insertCmd = new SqlCommand("INSERT INTO TestData VALUES (@ID, @Value)", myConn))
    {
        try
        {
            // ... add params
            affectedRows = insertCmd.ExecuteNonQuery();
        }
        catch (SqlException) { /*...*/ }
    }
    
    if (affectedRows == 0)
    {
        using (IDbCommand updateCmd = new SqlCommand("UPDATE TestData SET Value = @Value WHERE ID = @ID", myConn))
        {
            try
            {
                // ...add params
                affectedRows = updateCmd.ExecuteNonQuery();
            }
            catch (SqlException) { /*...*/ }
        }
    }
    

    (3)首先使用新ID执行SELECT查询,如果该行存在,请执行UPDATE其他INSERT查询

    bool dataExist = false;
    // ... 
    using (IDbCommand selectCmd = new SqlCommand("SELECT ID FROM TestDate WHERE ID=@ID", myConn))
    {
        try
        {
            // ... add param
            using (IDataReader reader = selectCmd.ExecuteReader())
                dataExist = reader.Read();
        }
        catch (SqlException) { /*...*/ }
    }
    if (dataExist) { /* update query, similar to above one*/ }
    else { /* insert, similar to above one */ }
    

    (4)执行一个大查询以执行所有选择更新或插入

    string query = "IF EXISTS (SELECT ID FROM TestData WHERE ID=@ID) " +
                   "UPDATE TestData SET Value = @Value WHERE ID = @ID " +
                   "ELSE INSERT INTO TestData VALUES (@ID, @Value)";
    
    using (IDbCommand bigQueryCmd = new SqlCommand(query, myConn))
    {
        try
        {
            // ... add param
            bigQueryCmd.ExecuteNonQuery();
        }
        catch (SqlException) { /*...*/ }
    }
    

1 个答案:

答案 0 :(得分:0)

您可以使用 MERGE

  

基于目标表执行插入,更新或删除操作   关于与源表的连接结果。

出于并发原因,使用 MERGE IF EXISTS/UPDATE/INSERT要好得多,而且只有一个语句,因此维护的代码更少:

类似的东西:

<强> SqlFiddleDemo

CREATE TABLE TestData (
   ID INT NOT NULL PRIMARY KEY,
   Value INT);

INSERT INTO TestData
VALUES (1,3);


DECLARE @id INT = 1, @value INT = 10;    -- will update
--DECLARE @id INT = 2, @value INT = 10;  -- will insert

;MERGE TestData AS TGT
USING (SELECT * FROM (SELECT @id AS ID, @value AS VALUE) AS t) AS SRC
   ON TGT.ID = SRC.ID
WHEN MATCHED THEN
   UPDATE SET Value = SRC.[VALUE]
WHEN NOT MATCHED THEN
   INSERT (ID, [VALUE])
   VALUES (SRC.ID, SRC.[VALUE]);

SELECT *
FROM TestData;