如何加快更新大量行的速度

时间:2011-01-18 13:44:52

标签: sql-server-2008 ado.net

我有一张包含1.400.000条目的表格。它是一个简单的文件清单

表格 - 文件

  • ID int
  • DocumentPath nvarchar
  • DocumentValid 位

我扫描目录并将目录中找到的任何文档设置为有效。

    public void SetReportsToValidated(List<int> validatedReports)
    {
        SqlConnection myCon = null;

        try
        {
            myCon = new SqlConnection(_conn);
            myCon.Open();

            foreach (int id in validatedReports)
            {                    
                SqlDataAdapter myAdap = new SqlDataAdapter("update_DocumentValidated", myCon);
                myAdap.SelectCommand.CommandType = CommandType.StoredProcedure;

                SqlParameter pId = new SqlParameter("@Id", SqlDbType.Int);
                pId.Value = id;
                myAdap.SelectCommand.Parameters.Add(pId); 

                myAdap.SelectCommand.ExecuteNonQuery();
            }
        }
        catch (SystemException ex)
        {
            _log.Error(ex);
            throw;
        }
        finally
        {
            if (myCon != null)
            {
                myCon.Close();
            }
        }
    }

更新的表现还可以,但我想要更多。将1000000个文档更新为有效需要1个多小时。有没有什么好方法可以加快更新速度?我正在考虑使用某种批处理(如表值参数)。 在SQLServer上进行配置时,每次更新大约需要5-10ms。

3 个答案:

答案 0 :(得分:2)

阅读报告并将它们一起添加到DataTable中(因为它们具有相同的维度),然后使用SqlBulkCopy对象上传整个内容。可能会更适合你。鉴于列数和行数很少,我认为你不会遇到内存问题。

答案 1 :(得分:2)

此时您正在为每条记录单独调用数据库。您可以使用SqlDataAdapter进行批量更新(简而言之):

1)定义一个SqlDataAdapter
2)将适配器上的.UpdateCommand设置为更新分组 3)在适配器上调用.Update方法,向其传递包含要更新的文档的ID的DataTable。这会将更新的行从DataTable批处理到DB,以批处理方式为每个记录调用sproc。您可以通过.BatchSize属性控制批量大小 4)所以你正在做的是删除手动,逐行循环,这对于批量更新是低效的。

见例子:
http://support.microsoft.com/kb/308055
http://www.c-sharpcorner.com/UploadFile/61b832/4430/


或者,你可以:
1)使用SqlBulkCopy将所有ID批量插入数据库中的 new 表(高效)
2)加载到该临时表后,运行单个SQL语句以从该临时表更新主表以验证文档。

见例子:
http://www.adathedev.co.uk/2010/02/sqlbulkcopy-bulk-load-to-sql-server.html
http://www.adathedev.co.uk/2011/01/sqlbulkcopy-to-sql-server-in-parallel.html

答案 2 :(得分:0)

不是每次在循环中创建适配器和参数,只需创建一次并为参数指定不同的值:

            SqlDataAdapter myAdap = new SqlDataAdapter("update_DocumentValidated", myCon);
            myAdap.SelectCommand.CommandType = CommandType.StoredProcedure;

            SqlParameter pId = new SqlParameter("@Id", SqlDbType.Int);
            myAdap.SelectCommand.Parameters.Add(pId); 

            foreach (int id in validatedReports)
            {
                myAdap.SelectCommand.Parameters[0].Value = id;  
                myAdap.SelectCommand.ExecuteNonQuery();
            }

这可能不会带来非常显着的改善,但与原始代码相比更好。此外,当您手动执行SqlCommand对象时,根本不需要适配器。只需直接使用SqlCommand。