从 C# 列表到 SQL Server 的批量插入到具有外键约束的多个表中

Cur*_*ddy 1 c# sql sql-server performance bulkinsert

我对这个问题完全一无所知,任何帮助将不胜感激:

我有两个表,一个是主数据表 ( Table A),另一个表 ( Table B) 与Table A.

我正在获取列表中的数据并希望将其插入 SQL Server 数据库中。

我目前使用下面的模式,但正在14分钟在插入100行Table A和在对应18个* 100行Table B

using (SqlConnection conn = new SqlConnection(conStr))
{
    foreach (var ticket in Tickets)
    {
        sql = string.Format(@"INSERT INTO dbo.Tickets([ColumnA], [ColumnB] ,..." + @")
                              VALUES(@ColumnA, @ColumnB,@ColumnC, @ColumnD, .... +
                            @"SELECT SCOPE_IDENTITY();");

        using (cmd = new SqlCommand(sql, conn))
        {
            cmd.Parameters.AddWithValue("@ColumnA", (object)ticket.Id ?? DBNull.Value);
            cmd.Parameters.AddWithValue("@ColumnB", (object)ticket.Address ?? DBNull.Value);
            cmd.Parameters.AddWithValue("@ColumnC", (object)ticket.Status?? DBNull.Value);
            ....

            conn.Open();
            TableA_TicketId = Convert.ToInt32(cmd.ExecuteScalar());
        }
    }
} 
Run Code Online (Sandbox Code Playgroud)

我用于SCOPE_IDENTITY()从表 A 中获取插入的每条记录的最新标识,并将其用于插入第二个表中

sql = string.Format(@"INSERT INTO Tickets_Fields ([TableA_TicketId], [FieldName], [Key],[Value]) 
                      VALUES (@TableA_TicketId, @FieldName, @Key, @Value);");

using (cmd = new SqlCommand(sql, conn))
{
    foreach (var customField in ticket.CustomFields)
    {
        cmd.Parameters.Clear();
        cmd.Parameters.AddWithValue("@TableA_TicketId", (object)TicketId ?? DBNull.Value);
        cmd.Parameters.AddWithValue("@FieldName", (object)"CustomField" ?? DBNull.Value);
        ...
        cmd.ExecuteNonQuery();
    }
}

conn.Close();
Run Code Online (Sandbox Code Playgroud)

请建议我是否可以通过任何方式提高此代码的性能。或者他们有更好/更快的方法吗?

sta*_*ica 5

一些想法:

  1. 在整个批量插入过程中保持相同的连接打开。在开始时打开它,然后在完成后才关闭它。

  2. 不要SqlCommand在每次循环迭代期间重新创建s。一开始就创建它们,然后只更新参数的值:cmd.Parameters["@x"].Value = …;

  3. 您通过foreach插入单个记录的循环插入到第二个表 (B) 中。您可以考虑将其替换为单个INSERT INTO TableB (x, y, z) SELECT x, y, z FROM @tvp,其中@tvp表值参数。本质上,这意味着您可以DataTable使用要插入到第二个表中的行填充例如 a ,然后将其DataTable作为@tvp. 从 SQL Server 2008 开始,IIRC 支持 TVP。第一次设置其中一个需要一些研究。

    (我不太确定上面的INSERT语句是否真的有效,或者 TVP 是否仅作为存储过程的参数起作用(参见例如这个例子)。)

  4. 比 #3 更进一步,将表 A 和 B 中的插入移到 DB 存储过程中。这个 SP 会将进入表 A 的值作为参数,以及带有进入表 B 的记录的表值参数。