C# SQL Server 2022 insert into too slow

gudnpqoy  于 2023-03-07  发布在  C#
关注(0)|答案(3)|浏览(164)

I created a simple table and inserted one thousand rows of data, but it took 10 seconds to insert only 1000 rows. Is this a normal insertion speed? It seems unusually slow. What could be the cause of this issue?

Create Table

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[DB](
    [CODE] [varchar](20) NOT NULL,
    [DATE] [datetime2](7) NOT NULL
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[DB] ADD  CONSTRAINT [DF_DB_DATE]  DEFAULT (getdate()) FOR [DATE]
GO

Insert Data

private void button1_Click(object sender, EventArgs e)
{
  for (int i = 1000; i < 2000; i++)
  {
    string query = $"INSERT INTO dbo.DB(CODE) VALUES('CHOCO{i}')";
    SqlExecuteNonQuery(query);
  }
}
private bool SqlExecuteNonQuery(string query)
{
  try
  {
    if (conn.State == ConnectionState.Closed)
      conn.Open();
    using (SqlCommand cmd = new SqlCommand(query, conn))
    {
      cmd.ExecuteNonQuery();
    }
  }
  catch (Exception ex)
  {
    return false;
  }
  finally
  {
    if (conn.State == ConnectionState.Open)
      conn.Close();
  }
  return true;
}
nzk0hqpo

nzk0hqpo1#

It's normal to be slow as you are inserting rows one by one. It will be better to pass the data to SQL Server stored procedure like XML, JSON or CSV like format. Then parse this data and put it in temporary table, perform some validations if needed and then insert the data at once:

INSERT INTO table
SELECT *
FROM #table
qf9go6mv

qf9go6mv2#

Did you try rebuild-index?

If you have more data then use bulk insert for better performance.

Regards,

xlpyo6sf

xlpyo6sf3#

At first I thought your problem was that you were opening your connection for each of the rows.

Than I did a simple Test Program but it looks like you are right, it takes around 10s =(. Edit: I remade my tests on a machine on the same network as the SQL Server Machine, the results were much better (more bellow)

Also, you should parametrize your query. ;)

static int Main(string[] args)
{
    try
    {
        var list = Enumerable.Range(1000, 1000).ToList();

        var sw = Stopwatch.StartNew();

        sw.Restart();
        NormalOpeningConnectionEachTime(list);
        Console.WriteLine(sw.ElapsedMilliseconds);

        sw.Restart();
        NormalUsingSameConnection(list);
        Console.WriteLine(sw.ElapsedMilliseconds);

        sw.Restart();
        BulkCopy(list);
        Console.WriteLine(sw.ElapsedMilliseconds);

        sw.Restart();
        MultipleValues(list);
        Console.WriteLine(sw.ElapsedMilliseconds);
        
        return 0;
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
        return 1;
    }
}

private static void NormalOpeningConnectionEachTime(IEnumerable<int> list)
{
    var query = "INSERT INTO dbo.DB(CODE) VALUES (@code)";

    using (var conn = new SqlConnection(ConnectionString))
    {
        foreach (var i in list)
        {
            try
            {
                if (conn.State == ConnectionState.Closed)
                    conn.Open();
                using (SqlCommand cmd = new SqlCommand(query, conn))
                {
                    cmd.Parameters.AddWithValue("@code", i);
                    cmd.ExecuteNonQuery();
                }
            }
            finally
            {
                if (conn.State == ConnectionState.Open)
                    conn.Close();
            }
        }
    }
}

private static void NormalUsingSameConnection(IEnumerable<int> list)
{
    var query = "INSERT INTO dbo.DB(CODE) VALUES (@code)";

    using (var connection = new SqlConnection(ConnectionString))
    using (var cmd = new SqlCommand(query, connection))
    {
        connection.Open();
        cmd.Parameters.Add(new SqlParameter("@code", SqlDbType.Int));
        foreach (var i in list)
        {
            cmd.Parameters[0].Value = i;
            cmd.ExecuteNonQuery();
        }
    }
}

private static void BulkCopy(IEnumerable<int> list)
{
    using (var table = new DataTable())
    using (var bulkCopy = new SqlBulkCopy(ConnectionString))
    {
        table.Columns.Add("CODE");

        bulkCopy.DestinationTableName = "dbo.[DB]";
        bulkCopy.BatchSize = 1000;
        foreach (DataColumn column in table.Columns)
        {
            bulkCopy.ColumnMappings.Add(column.ColumnName, column.ColumnName);
        }

        foreach (var i in list)
        {
            table.Rows.Add(i);
        }

        //Attention - At this point the table has all data, but you could WriteToServer when the numberOfRows is more than BatchSize, so to not overload memory (clearing the rows after).
        bulkCopy.WriteToServer(table);
    }
}

private static void MultipleValues(IEnumerable<int> list)
{
    void Execute(List<SqlParameter> parameters)
    {
        var query = $"INSERT INTO dbo.DB(CODE) VALUES {(string.Join(",", parameters.Select(x => $"({x.ParameterName})")))}";

        using (var connection = new SqlConnection(ConnectionString))
        using (var cmd = new SqlCommand(query, connection))
        {
            foreach (var s in parameters)
            {
                cmd.Parameters.Add(s);
            }

            connection.Open();
            cmd.ExecuteNonQuery();
        }
    }

    var parameters = new List<SqlParameter>();
    foreach (var i in list)
    {
        parameters.Add(new SqlParameter($"@code{i}", SqlDbType.Int) { Value = i });

        //Parameter limit is 1000
        if (parameters.Count >= 1000)
        {
            Execute(parameters);
            parameters.Clear();
        }
    }

    if (parameters.Any())
    {
        Execute(parameters);
    }
}

The results were (in ms)

A) Using the same network
| # | EachTime | SameConnection | BulkCopy | MultipleValues |
| ------------ | ------------ | ------------ | ------------ | ------------ |
| 1 | 1182 | 489 | 252 | 39 |
| 2 | 891 | 503 | 13 | 44 |
| 3 | 876 | 497 | 13 | 34 |
| 4 | 870 | 629 | 13 | 44 |
| 5 | 879 | 549 | 12 | 37 |
| 6 | 888 | 604 | 12 | 43 |
| 7 | 890 | 561 | 18 | 40 |
| 8 | 889 | 518 | 12 | 35 |
| 9 | 868 | 534 | 12 | 34 |
| 10 | 868 | 541 | 18 | 34 |
| -------- | -------------- | -------------- | -------------- | -------------- |
| Average | 910 | 543 | 38 | 38 |

B) Over the Internet

#EachTimeSameConnectionBulkCopyMultipleValues
010431101084165
110235102473969
21036497533682
31002599814767
41010599354164
59877102414064
610519105173465
710441112464564
810350103184366
910605106304071
---------------------------------------------------------------
Average10295102974067

相关问题