加快读取文本文件到sql表的最佳方法是什么?

时间:2014-04-04 13:20:10

标签: c# asp.net sql-server wcf

我知道很多次都会问这个问题,但我的问题略有不同:

我的要求如下:

我有一个约有的文本文件。 50000行,文件差不多10 MB。

每一行都有固定大小的值,如下所示:

0001            abcdefgh          1234567         xyz
0002            pqrst             02233           abc
003             asddfd            545             slfkk

它不是分隔符或逗号分隔等。

我有一个sql表,结构如下:

code varchar(5)
name varchar(18)
phone varchar(16)
address varchar(20)

我需要完成的是当客户点击按钮时,它应该清空sql表并从文本文件中读取新记录(因为这是一个ASP.net应用程序,我使用WCF服务来读取文件并将字符串传递给服务器,其工作正常)。

拆分和保存到数据库的代码如下:

       Service1Client client = new Service1Client();
       string data = client.ReadFile(@"C:\testfolder\test.txt");


        context.Database.ExecuteSqlCommand(@"DELETE FROM table1");

       table1 c;


        using (StringReader reader = new StringReader(data))
        {
            string line = "";

            while ((line = reader.ReadLine()) != null)
            {
                c = new table1();
                c.Code = line.Substring(0, 5).Trim();
                c.name= line.Substring(5, 18).Trim();
                c.phone= line.Substring(23, 16).Trim();
                c.address = line.Substring(39, 20).Trim();
                context.table1.Add(c);
            }
        }
        context.SaveChanges();
    }
    client.Close();

但这种方法至少需要30分钟才能复制所有记录。有没有更好的方法加快这个?

感谢

4 个答案:

答案 0 :(得分:1)

读取文件不是花时间,而是插入数据库。 我会以下面的方式修改它,而不是一次性执行更新,以较小的批次执行:

您可以通过更改if语句来测试性能,以查看您在批处理中插入的行数。

using (StringReader reader = new StringReader(data))
    {
        string line = "";
        int counter = 0;
        while ((line = reader.ReadLine()) != null)
        {
            c = new table1();
            c.Code = line.Substring(0, 5).Trim();
            c.name= line.Substring(5, 18).Trim();
            c.phone= line.Substring(23, 16).Trim();
            c.address = line.Substring(39, 20).Trim();
            context.table1.Add(c);
            if (counter == 10){
              context.SaveChanges();
              counter =0;
           }
           else{
              counter++;
           }
        }
        context.SaveChanges();
    }

或者,您可以设计一个producer/consumer模型,其中文件的读取与数据库插入无关,因此实质上您将运行2个线程,1个线程读取,另一个插入数据库。将多于一个的线程插入到DB中将无济于事,但是独立于DB插入的读取可能会提高整体性能。

答案 1 :(得分:1)

作为数据库主管,我打算说" BCP"但是......使用SqlBulkCopy。见文章:

http://msdn.microsoft.com/en-us/library/7ek5da1a%28v=vs.110%29.aspx

" Microsoft SQL Server包含一个名为bcp的流行命令行实用程序,用于将大型文件快速批量复制到SQL Server数据库中的表或视图中。 SqlBulkCopy类允许您编写提供类似功能的托管代码解决方案。还有其他方法可以将数据加载到SQL Server表中(例如INSERT语句),但SqlBulkCopy比它们具有显着的性能优势。"

答案 2 :(得分:0)

你一次只读一行,这是非常低效的。您应该使用BufferedStream:

  

缓冲区是内存中用于缓存数据的字节块,从而   减少对操作系统的调用次数。缓冲区改善   读写性能。缓冲区可用于读取或   写作,但从不同时。读写方法   BufferedStream自动维护缓冲区。

答案 3 :(得分:0)

进行中介SaveChanges并用新的上下文替换你的上下文:

    context.Configuration.AutoDetectChangesEnabled = false;
    int lines = 0;
    int batchSize=50;
    using (StringReader reader = new StringReader(data))
    {
        string line = "";

        while ((line = reader.ReadLine()) != null)
        {
            c = new table1();
            c.Code = line.Substring(0, 5).Trim();
            c.name= line.Substring(5, 18).Trim();
            c.phone= line.Substring(23, 16).Trim();
            c.address = line.Substring(39, 20).Trim();
            context.table1.Add(c);

            if (lines++ % batchSize == 0)
            {
                context.SaveChanges();
                context = new DataContext();
                context.Configuration.AutoDetectChangesEnabled = false;
            }
        }
    }
    context.SaveChanges();

您可以调整batchSize