如何加速这个 C# 函数 / SQL 插入?

4

这段代码将整数数组序列化,然后插入到一个SQL表中。但是它没有达到我需要的速度。我是否可以更高效地做些什么?

谢谢!

    public void SetItem(long Id, int[] items)
    {
        using (MemoryStream stream = new MemoryStream())
        {
            foreach (int d in items)
            {
                var bin = BitConverter.GetBytes(d); //Serialize
                stream.Write(bin, 0, bin.Length);
            }
            var array = stream.ToArray();

            using (SqlCommand cmd = new SqlCommand("INSERT INTO Items(Id, Item, DateCreated) VALUES (@Id, @binaryValue, @dateCreated)", sqlConnection))
            {
                cmd.Parameters.Add("@binaryValue", SqlDbType.VarBinary, array.Length).Value = array;
                cmd.Parameters.Add("@Id", SqlDbType.BigInt).Value = Id;
                cmd.Parameters.Add("@dateCreated", SqlDbType.DateTime2).Value = DateTime.Now;
                cmd.ExecuteNonQuery();
            }
        }
    }

你尝试过在MemoryStream周围包装BinaryWriter,而不是使用BitConverter吗?另外,既然最终要将其转换为数组,为什么要使用流而不是数组?你已经知道大小了(items.Count * 4)。 - Claus Jørgensen
sqlConnection是一个私有变量吗? - rsbarro
是的,sqlConnection是一个私有变量。 - user404068
@user404068:按照发布的代码来看,我觉得它不会运行得太慢。你是否多次调用了SetItem?你是否重复使用sqlConnection或每次都打开一个新连接?你能提供一些时间数据,说明第一个块(在其中转换数据)和第二个块(在其中写入数据库)执行所需的时间吗?可能是转换很快,而写入需要更长时间(例如由于表上的索引)。 - rsbarro
代码示例存在一个严重的缺陷,它无法插入你 75% 的字节,所以当我意识到这个问题时,我又将其删除了。 - Claus Jørgensen
显示剩余2条评论
5个回答

10

我建议您将此函数分为两个部分。一个处理字节数组,另一个用于插入到数据库中。

然后运行性能分析,查看您的字节数组代码是否慢或者是数据库问题。

也许您试图加速并不缓慢的东西 :)


6
如果你要插入大量数据行,使用SqlBulkCopy类比多次调用insert更快。请参考这篇博客文章中的示例

嗯...他正在进行单个插入。 - BlackTigerX

1

我会尝试的第一件事是为内存流预分配byte[]

var array = new int[BitConverter.GetBytes(0).Length * items.Length];
using (MemoryStream stream = new MemoryStream(array))
{
    // ... rest is almost the same
}

1
你可以创建一个存储过程,使用插入命令。这样会更快,因为存储过程已经编译好了Sql。
类似这样:
    SqlConnection conn = new SqlConnection(actual_string);
conn.Open();

// Create the command string
SqlCommand cmd = new SqlCommand("EXEC insert_test @var1, @var2, @var3, @str1, @str2", conn);

// Iterate through all of the objects
try {
    for (int i = 0; i < 10000; i++) {
        cmd.Parameters.Clear();
        cmd.Parameters.Add(new SqlParameter("@var1", var1));
        cmd.Parameters.Add(new SqlParameter("@var2", var2));
        cmd.Parameters.Add(new SqlParameter("@var3", var3));
        cmd.Parameters.Add(new SqlParameter("@str1", str1));
        cmd.Parameters.Add(new SqlParameter("@str2", str2));

        // Read in all the data
        cmd.ExecuteNonQuery();
    }
} finally {
    conn.Close();
}

但我的偏好是将XML发送到一个过程中。

您可以在这个好文章中了解更多。


1

我的第一個傾向是預先分配一個數組,供MemoryStream使用,然後使用BinaryWriter來寫入它:

var OutputArray = new byte[items.Length * 4];
using (var ms = new MemoryStream(OutputArray))
{
    using (var writer = new BinaryWriter(ms))
    {
        foreach (var i in items)
        {
            writer.Write(i);
        }
    }
}
// You can now send the OutputArray to SQL server

BinaryWriter 不会在内部使用 BitConverter.GetBytes。相反,它从 int 中一次提取一个字节并将其放入缓冲区中。然后将缓冲区写入流。另一方面,BitConverter 在每次调用时都会分配一个新的 4 字节缓冲区。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接