c# - 使用 C# 在 SQL Server 的临时表中插入 30,000 行的最快方法

标签 c# sql sql-server bulkinsert sqlbulkcopy

我正在尝试了解如何使用 C# 提高在 SQL Server 中的临时表中的插入性能。有些人说我应该使用 SQLBulkCopy,但是我一定是做错了什么,因为它似乎比简单地构建 SQL 插入字符串慢得多。

我使用 SQLBulkCopy 创建表的代码如下:

public void MakeTable(string tableName, List<string> ids, SqlConnection connection)
    {

        SqlCommand cmd = new SqlCommand("CREATE TABLE ##" + tableName + " (ID int)", connection);
        cmd.ExecuteNonQuery();

        DataTable localTempTable = new DataTable(tableName);

        DataColumn id = new DataColumn();
        id.DataType = System.Type.GetType("System.Int32");
        id.ColumnName = "ID";
        localTempTable.Columns.Add(id);

        foreach (var item in ids)
        {
             DataRow row = localTempTable.NewRow();
             row[0] = item;
             localTempTable.Rows.Add(row);
             localTempTable.AcceptChanges();
        }


        using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
        {
            bulkCopy.DestinationTableName = "##" + tableName;
            bulkCopy.WriteToServer(localTempTable);

        }
    }

这样我的插入需要很长时间才能运行。我以另一种方式让我的插件工作得更快:

我将插入位创建为字符串,并将其连接到我的 SQL 创建临时表语句中:

插入字符串的创建:

public string prepareInserts(string tableName, List<string> ids)
    {
        List<string> inserts = new List<string>();

        var total = ids.Select(p => p).Count();
        var size = 1000;

        var insert = 1;

        var skip = size * (insert - 1);

        var canPage = skip < total;

        while (canPage)
        {
            inserts.Add(" insert into ##" + tableName + @" (ID) values " + String.Join(",", ids.Select(p => string.Format("({0})", p))
                        .Skip(skip)
                        .Take(size)
                        .ToArray()));
            insert++;
            skip = size * (insert - 1);
            canPage = skip < total;
        }

        string joinedInserts = String.Join("\r\n", inserts.ToArray());

        return joinedInserts;

    }

创建查询后在 SQL 语句中使用它们:

inserts = prepareInserts(tableName, ids);

var query = @"IF EXISTS
                                            (
                                            SELECT *
                                            FROM tempdb.dbo.sysobjects
                                            WHERE ID = OBJECT_ID(N'tempdb..##" + tableName + @"')
                                            )
                                                BEGIN
                                                    DELETE FROM ##" + tableName + @"
                                                END
                                            ELSE
                                                BEGIN
                                                    CREATE TABLE ##" + tableName + @"
                                                    (ID int)
                                                END " + inserts;

            var command = new SqlCommand(query, sqlConnection);
...

自从我看到有人告诉我(在堆栈交换 https://dba.stackexchange.com/questions/44217/fastest-way-to-insert-30-thousand-rows-in-sql-server/44222?noredirect=1#comment78137_44222 上)我应该使用 SQLBulkCopy 并且那样会更快我相信我应该改进我做这件事的方式。因此,如果有人可以建议我如何改进我的 SQLBulkCopy 代码,或者告诉我是否有更好的插入语句可以提高我的应用程序的性能,那就太好了。

最佳答案

您的问题可能在 localTempTable.AcceptChanges(); 因为它提交了您的更改。
如果你做下一个,我认为它会运行得更快

    foreach (var item in ids)
    {
         DataRow row = localTempTable.NewRow();
         row[0] = item;
         localTempTable.Rows.Add(row);

    }

    localTempTable.AcceptChanges();

    using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
    {
        bulkCopy.DestinationTableName = "##" + tableName;
        bulkCopy.WriteToServer(localTempTable);

    }

来自 MSDN - DataSet.AcceptChanges

Commits all the changes made to this DataSet since it was loaded or since the last time AcceptChanges was called.

关于c# - 使用 C# 在 SQL Server 的临时表中插入 30,000 行的最快方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17028657/

相关文章:

c# - 在 Windows 8 应用程序中使用 HttpClient 的并行 HTTPRequest

c# - 为大型下载配置 httpRuntime 执行超时

java - 为什么 C# 和 Java 等高级语言不强制文件关闭?

sql - MySQL - 仅在每个分组值的第一个实例中显示字段值?

mysql - 我需要多表查询中的空字段

sql - 如何在select语句中检查列值是否为空

sql-server - SQL Server 2005中的tran和transaction有什么区别

sql-server - 运行 ms sql local db express

c# - System.Drawing.Bitmap 包含比预期更多的数据

java - 使用 TSQL 解析 Apple plist