【问题标题】:How to input into DataTable quickly? Or save data permanently into DataTable?如何快速输入DataTable?或者将数据永久保存到 DataTable 中?
【发布时间】:2019-06-20 10:22:08
【问题描述】:

我将文本文件输入到 DataTable 中,然后使用 SqlBulkCopy 复制到数据库中。虽然 BulkCopy 速度很快,但将 50000 多行插入 DataTable 却不是(大约 5 分钟)。如何提高效率?

我可以快速向 DataTable 中插入数据吗? 如果没有,有没有办法将插入的数据永久保存到 DataTable 中,这样我就不必每次运行程序时都插入它?

    for (; i < fares.Length; )
            {
                k = i;
                Console.WriteLine("Inserting " + k + " out of " + (fares.Length));
                for (; i <= (k + 3); i++)
                {
                    if (i % 4 == 0)
                    {
                        for (int j = 0; j < fares.Length - 1; j++)
                        {
                            {
                                int space = fares[i].IndexOf(" ");
                                startStation = fares[i].Substring(0, space);

                                endStation = fares[i].Substring(space + 1, fares[i].Length - space - 1);

                            }
                        }
                    }

                    else if (i % 4 == 1)
                    {
                        valueFare = fares[i];
                    }
                    else if (i % 4 == 2)
                    {
                        standardFare = fares[i];

                    }
                    else if (i % 4 == 3)
                    {
                        time = int.Parse(fares[i]);
                    }


                }

                faresDT.Rows.Add(startStation, endStation, valueFare, standardFare, time);

【问题讨论】:

  • 50k 行并不多。创建Datatable 的代码在哪里?
  • 我会完全摆脱数据表,直接将文件读入sqlbulkcopy,但是没有更多示例代码,很难提供帮助
  • 我刚刚添加了将数据插入DataTable的代码
  • 该代码所做的不仅仅是插入数据表。向控制台写入 50,000 次将需要一些时间,解析也需要一些时间。总而言之,你在问令人费解的问题

标签: c# sql database datatable


【解决方案1】:

如果您想要优化对数据库的负载,我建议您完全摆脱 DataTable。通过使用 Marc Gravell 的 FastMember(以及任何使用 SqlBulkCopy 的人都应该使用 FastMember 恕我直言),您可以直接从任何 IEnumerable 获取 DataReader。

每当从文件直接写入数据库时​​,我都会使用以下代码的一些变体。下面的代码将通过巧妙地使用收益返回和 IEnumerable 的延迟加载,将文件的内容直接流式传输到 SqlBulkCopy 操作。

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.IO;
using System.Text;
using FastMember;

namespace BulkCopyTest
{
    public class Program
    {
        public static void Main(string[] args)
        {
            const string filePath = "SOME FILE THAT YOU WANT TO LOAD TO A DB";

            WriteData(GetData<dynamic>(filePath));
        }

        private static void WriteData<T>(IEnumerable<T> data)
        {
            using (var bcp = new SqlBulkCopy(GetConnection(), SqlBulkCopyOptions.TableLock, null))
            using (var reader = ObjectReader.Create(data))
            {
                SetColumnMappings<T>(bcp.ColumnMappings);
                bcp.BulkCopyTimeout = 300;
                bcp.BatchSize = 150000;
                bcp.DestinationTableName = ""; //TODO: Set correct TableName
                bcp.WriteToServer(reader);
            }
        }

        private static void SetColumnMappings<T>(SqlBulkCopyColumnMappingCollection mappings)
        {
            //Setup your column mappings
        }


        private static IEnumerable<T> GetData<T>(string filePath)
        {
            using (var fileStream = File.OpenRead(filePath))
            using (var reader = new StreamReader(fileStream, Encoding.UTF8))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    //TODO: Add actual parsing logic and whatever else is needed to create an instance of T
                    yield return Activator.CreateInstance<T>();
                }
            }
        }

        private static SqlConnection GetConnection()
        {
            return new SqlConnection(new SqlConnectionStringBuilder
            {
                //TODO: Set Connection information here
            }.ConnectionString);
        }
    }
}

【讨论】:

    【解决方案2】:

    在这种情况下,我认为您应该利用 DataTable 类中提供的 BeginLoadData、LoadDataRow 和 EndLoadData 方法,您可以像这样使用它们:

    try
    {
        faresDT.BeginLoadData();
    
        // Your for loop...
        {
            // Logic defining the value of startStation, endStation, valueFare, standardFare and time removed for briefness.
            faresDT.LoadDataRow(new object[] {startStation, endStation, valueFare, standardFare, time}, true);
        }
    }
    finally
    {
        faresDT.EndLoadData();
    }
    

    BeginLoadData() 的作用是关闭每次添加行时发生的一些处理,并且仅在通过调用 EndLoadData() 完成加载数据时执行一次。

    您可以在此处找到有关这些 API 的更多详细信息: https://docs.microsoft.com/en-us/dotnet/api/system.data.datatable.loaddatarow?view=netframework-4.7.2

    【讨论】:

      猜你喜欢
      • 2016-04-11
      • 2011-09-02
      • 2010-09-24
      • 2015-10-14
      • 2019-06-28
      • 1970-01-01
      • 2013-09-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多