我需要更新MS SQL Server数据库的2个表。
对于每个“事件”,我都会生成2个查询:
因此,对于每个事件,我都有一个查询,例如:
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);
}
}
答案 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。
可以合并解决方案以获得更好的结果。