繁体   English   中英

SqlBulkCopy 数据表,因为它们被添加到数据集中

[英]SqlBulkCopy DataTables as they are added to a DataSet

我想将 csv 中的值解析为数据表块,将它们添加到数据集,然后使用 SQLBulkCopy 将数据表插入到 SQL 中的单个表中。 原始 csv 的范围可以从 4 GB 到 8 GB,我需要避免将整个内容读入内存,因此分块。 我粗略地根据这篇文章进行了分块。 我使用LumenWorks来解析 csv 值。

将数据表添加到数据集后,我想使用 SqlBulkCopy 将其插入到我的 SQL 表中,同时创建下一个数据表。 SqlBulkCopy 完成后,我想删除数据表以释放内存。

我的第一个想法是在没有 await 的情况下异步运行分块方法,然后运行一个 while 循环来检查数据集中是否存在下一个数据表。 如果数据表存在,则批量复制。 如果数据表行数小于行限制,则它是最后一个块并停止 while 循环。

我会以错误的方式解决这个问题吗? 如果没有,我怎么能做这样的事情?

        string filePath = @"C:\Users\user\Downloads\Testing\file - Copy.csv";
        DataSet ds = new DataSet();

        bool continueInsert = true;
        int rowLimit = 100000;
        int tableNumber = 0;

        //Start this, but do not wait for it to complete before starting while loop
        ChunkCSV(filePath, ds, rowLimit);

        //Run SqlBulkCopy if datatable exists 
        while (continueInsert)
        {
            if (ds.Tables.Contains("tbl_" + tableNumber))
            {
                DataTable dataTable = ds.Tables["tbl_" + tableNumber];

                //SqlBulkCopy dataTable code HERE

                if (ds.Tables["tbl_" + tableNumber].Rows.Count < rowLimit)
                {
                    continueInsert = false;
                }

                //Remove datatable from dataset to release memory
                ds.Tables.Remove("tbl_" + tableNumber);

                tableNumber++;
            }
            else
            {
                Thread.Sleep(1000);
            }
        }

这是我的分块代码:

    private static void ChunkCSV(string filePath, DataSet dataSet, int rowLimit)
    {
        char delimiter = ',';

        DataTable dtChunk = null;
        int tableNumber = 0;
        int chunkRowCount = 0;
        bool firstLineOfChunk = true;

        using (var sr = new StreamReader(filePath))
        using (CsvReader csv = new CsvReader(sr, false, delimiter, '\"', '\0', '\0', ValueTrimmingOptions.All, 65536))
        {
            int fieldCount = csv.FieldCount;
            string[] row = new string[fieldCount];

            //Add fields when necessary
            csv.MissingFieldAction = MissingFieldAction.ReplaceByEmpty;

            while (csv.ReadNextRecord())
            {
                if (firstLineOfChunk)
                {
                    firstLineOfChunk = false;
                    dtChunk = CreateDataTable(fieldCount, tableNumber);
                }

                DataRow dataRow = dtChunk.NewRow();

                csv.CopyCurrentRecordTo(row);
                for (int f = 0; f < fieldCount; f++)
                {
                    dataRow[f] = row[f];
                }

                dtChunk.Rows.Add(dataRow);
                chunkRowCount++;

                if (chunkRowCount == rowLimit)
                {
                    firstLineOfChunk = true;
                    chunkRowCount = 0;
                    tableNumber++;
                    dataSet.Tables.Add(dtChunk);
                    dtChunk = null;
                }
            }
        }

        if (dtChunk != null)
        {
            dataSet.Tables.Add(dtChunk);
        }

    }
    private static DataTable CreateDataTable(int fieldCount, int tableNumber)
    {
        DataTable dt = new DataTable("tbl_" + tableNumber);

        for(int i = 0; i < fieldCount; i++)
        {
            dt.Columns.Add("Column_" + i);
        }

        return dt;
    }

没有理由一开始就使用 DataTable。

使用SqlBulkCopy.WriteToServer(IDataReader)重载,您可以将整个文件直接流式传输到 SQL Server。 如果您不想在单个事务中加载所有行,请使用SqlBulkCopy.BatchSize

例如

using (var sr = new StreamReader(filePath))
using (CsvReader csv = new CsvReader(sr, false, delimiter, '\"', '\0', '\0', ValueTrimmingOptions.All, 65536))
{
    bulkCopy.WriteToServer(csv);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM