sqlbulkcopy mem.управление - PullRequest
       14

sqlbulkcopy mem.управление

1 голос
/ 02 августа 2010

Я использую SQLBULKCOPY для копирования некоторых таблиц данных в таблицу базы данных, однако, поскольку размер копируемых файлов иногда превышает 600 МБ, у меня не хватает памяти.

Я надеюсь получить несколько советов по управлению размером таблицы, прежде чем помещать ее в базу данных, чтобы я мог освободить часть памяти для продолжения записи.

Вот несколько примеров моего кода (некоторые столбцы и строкиисключено для простоты)

            SqlBulkCopy sqlbulkCopy = new SqlBulkCopy(ServerConfiguration); //Define the Server Configuration
        System.IO.StreamReader rdr = new System.IO.StreamReader(fileName);

        Console.WriteLine("Counting number of lines...");
        Console.WriteLine("{0}, Contains: {1} Lines", fileName, countLines(fileName));

        DataTable dt = new DataTable();

        sqlbulkCopy.DestinationTableName = "[dbo].[buy.com]"; //You need to define the target table name where the data will be copied
        dt.Columns.Add("PROGRAMNAME");
        dt.Columns.Add("PROGRAMURL");
        dt.Columns.Add("CATALOGNAME");

        string inputLine = "";
        DataRow row; //Declare a row, which will be added to the above data table

        while ((inputLine = rdr.ReadLine()) != null) //Read while the line is not null
            {
                i = 0;
                string[] arr;

                Console.Write("\rWriting Line: {0}", k);
                arr = inputLine.Split('\t'); //splitting the line which was read by the stream reader object (tab delimited)
                row = dt.NewRow();
                row["PROGRAMNAME"] = arr[i++];
                row["PROGRAMURL"] = arr[i++];
                row["CATALOGNAME"] = arr[i++];
                row["LASTUPDATED"] = arr[i++];
                row["NAME"] = arr[i++];
                dt.Rows.Add(row);
                k++;
        }

        // Set the timeout, 600 secons (10 minutes) given table size--damn that's a lota hooch
        sqlbulkCopy.BulkCopyTimeout = 600;
        try
        {
            sqlbulkCopy.WriteToServer(dt);
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
        sqlbulkCopy.Close();//Release the resources
        dt.Dispose();

        Console.WriteLine("\nDB Table Written: \"{0}\" \n\n", sqlbulkCopy.DestinationTableName.ToString());

    }

У меня продолжали возникать проблемы с запуском SQLBulkCopy, и я понял, что мне нужно проделать больше работы над каждой записью, прежде чем она будет введена в базу данных, поэтому я разработалпростой метод LinQ to Sql, позволяющий делать записи по обновлениям записей, чтобы я мог редактировать другую информацию и создавать дополнительную информацию о записи во время ее запуска,

Проблема: этот метод работает довольно медленно (даже на компьютере с Core i3)Любые идеи о том, как ускорить его (многопоточность?) - на одном процессорном ядре, с 1 ГБ памяти это иногда дает сбой или занимает6-8 часов, чтобы написать тот же объем данных, что и один SQLBulkCopy, который занимает несколько минут.Тем не менее, он лучше управляет памятью.

            while ((inputLine = rdr.ReadLine()) != null) //Read while the line is not null
        {
            Console.Write("\rWriting Line: {0}", k);
            string[] arr;              
            arr = inputLine.Split('\t');

            /* items */
            if (fileName.Contains(",,"))
            {
                Item = Table(arr);
               table.tables.InsertOnSubmit(Item);

                /* Check to see if the item is in the db */
                bool exists = table.tables.Where(u => u.ProductID == Item.ProductID).Any();

                /* Commit */
                if (!exists)
                {
                    try
                    {
                        table.SubmitChanges();
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                        // Make some adjustments.
                        // ...
                        // Try again.
                        table.SubmitChanges();
                    }
                }
            }

С помощью вспомогательного метода:

    public static class extensionMethods
{
    /// <summary>
    /// Method that provides the T-SQL EXISTS call for any IQueryable (thus extending Linq).
    /// </summary>
    /// <remarks>Returns whether or not the predicate conditions exists at least one time.</remarks>
    public static bool Exists<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate)
    {
        return source.Where(predicate).Any();
    }
}

Ответы [ 2 ]

2 голосов
/ 02 августа 2010

Попробуйте указать для свойства BatchSize значение 1000, что позволит объединить вставку в пакет из 1000 записей, а не из всей партии.Вы можете настроить это значение, чтобы найти оптимальное.Я использовал sqlbulkcopy для данных аналогичного размера, и он работает хорошо.

1 голос
/ 10 апреля 2015

Столкнувшись с той же проблемой, обнаружил, что проблема исключения OutOfMemory была в DataTable.Rows ограничения максимального количества.Решено с воссозданием таблицы, с максимальным пределом 500000 строк.Надеюсь, мое решение будет полезным:

var myTable = new System.Data.DataTable();
myTable.Columns.Add("Guid", typeof(Guid));
myTable.Columns.Add("Name", typeof(string));

int counter = 0;

foreach (var row in rows)
{
    ++counter;

    if (counter < 500000)
    {
        myTable.Rows.Add(
            new object[]
            {
                row.Value.Guid,
                row.Value.Name
            });
    }
    else
    {
        using (var dbConnection = new SqlConnection("Source=localhost;..."))
        {
            dbConnection.Open();
            using (var s = new SqlBulkCopy(dbConnection))
            {
                s.DestinationTableName = "MyTable";

                foreach (var column in myTable.Columns)
                    s.ColumnMappings.Add(column.ToString(), column.ToString());

                try
                {
                    s.WriteToServer(myTable);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
                finally
                {
                    s.Close();
                }
            }
        }

        myTable = new System.Data.DataTable();
        myTable.Columns.Add("Guid", typeof(Guid));
        myTable.Columns.Add("Name", typeof(string));

        myTable.Rows.Add(
            new object[]
            {
                row.Value.Guid,
                row.Value.Name
            });

        counter = 0;

    }
}
...