如何加快聚合SQL插入?

时间:2019-02-28 12:48:05

标签: c# sql-server

我需要更新MS SQL Server数据库的2个表。

对于每个“事件”,我都会生成2个查询:

  1. 表A中的插入
  2. 表B中相关行的更新

因此,对于每个事件,我都有一个查询,例如:

cmdA = "INSERT INTO [TableA] very complex referncing TableB"
cmdB = "UPDATE [TableB] SET very complex referencing TableA"

由于查询相互引用,因此我无法执行某种表上载方法。

我有一个事件队列,该事件队列被另一个线程填充,因此我需要尽快执行cmdA和cmdB。逐个事件运行队列事件太慢。因此,我通过获取所有当前队列事件并将它们与“;”连接来创建一个聚合命令。

  

aggCmdTxt = cmdA; cmdB; cmdA; cmdB; cmdA; cmdB; cmdA; cmdB ...

然后我使用下面的InsertOrdersFromTxt执行此聚合命令。

对于每个事件,这比运行cmdA和cmdB的速度快得多,但仍然很慢。如果队列中有30个事件,则可能需要500毫秒。

看来,我的聚合命令中的子查询数量成比例地影响了执行时间。我当然希望如此-但是我可以使其更有效率吗?

public void InsertOrdersFromTxt(string aggCmdText)
{
    SqlCommand cmd;

    try
    {
        cmd = new SqlCommand(aggCmdText, conn);

        cmd.ExecuteNonQuery();
    }
    catch (Exception err)
    {
        throw new Exception("[InsertOrdersFromTxt] Error: " + err.Message);
    }
}

3 个答案:

答案 0 :(得分:2)

使用基于集合的方法是SQL Server的最佳方法。因此,请尝试使用以下方法。

如果您要基于Table B的某些条件更新数据Table A,则可以仅将数据发送到存储过程中,该存储过程可以更新Table B的数据:

C#:

// creating table-valued parameter
var yourDataTable = new DataTable();
yourDataTable.Columns.Add("ID", typeof(int));
yourDataTable.Columns.Add("CarNumber");

//inserting data into table valued parameter
yourDataTable.Rows.Add(1, "Hello, World!");

//Parameter declaration
SqlParameter[] Parameter = new SqlParameter[1];    
Parameter[0].ParameterName = "@FooParameters";    
Parameter[0].SqlDbType = SqlDbType.Structured;    
Parameter[0].Value = yourDataTable;    

// Executing Stored Procedure
SqlHelper.ExecuteNonQuery(this.ConnectionString, CommandType.StoredProcedure, " 
    [YourStoredProcedure]", Parameter);  

然后在SQL Server中创建表值参数:

CREATE TYPE [dbo].[tp_YourTP] AS TABLE(
    [ID] [INT] NOT NULL,
    [CarNumber] [VARCHAR](255) NULL
)
GO

然后您可以在存储过程中使用此表参数:

DROP PROCEDURE IF EXISTS YourStoredProcedure
GO 

CREATE PROCEDURE dbo.YourStoredProcedure(     
      @FooParams  tp_YourTP  READONLY        
)
AS
   UPDATE t_A
   SET t_A.CarNumber = t_B.CarNumber
   FROM TableA AS t_A
   INNER JOIN @FooParams  AS t_B ON t_A.ID = t_B.ID

答案 1 :(得分:0)

请检查以下内容:

using (connection)
{
    SqlCommand command = new SqlCommand(
      "SELECT CategoryID, CategoryName FROM dbo.Categories;" +
      "SELECT EmployeeID, LastName FROM dbo.Employees",
      connection);
    connection.Open();

    SqlDataReader reader = command.ExecuteReader();

    while (reader.HasRows)
    {
        Console.WriteLine("\t{0}\t{1}", reader.GetName(0),
            reader.GetName(1));

        while (reader.Read())
        {
            Console.WriteLine("\t{0}\t{1}", reader.GetInt32(0),
                reader.GetString(1));
        }
        reader.NextResult();
    }
}

答案 2 :(得分:0)

一个缺点是,更新要慢得多,然后插入。所以,

解决方案1: 将所有插入语句打包为一个语句并执行。为了进行更新,请从表中读取基于PK的行,并删除表中的所有行。然后对所有行执行插入语句,而不是更新stm。

解决方案2: 通过SqlBulkCopy类使用批量插入。 前https://www.csvreader.com/code/cs/bulk_insert_csv.php

解决方案3: 在C#中使用异步编程可以批量执行您的语句。这样,您的主线程将不会因sql操作而停止。

解决方案4: 创建连接池。使用多线程更新分别更新表A和B。

可以合并解决方案以获得更好的结果。