sqlbulkcopy mem. Management

datatable memory sqlbulkcopy

Frage

Ich benutze SQLBULKCOPY, um einige Datentabellen in eine Datenbanktabelle zu kopieren, da die Größe der Dateien, die ich kopiere, manchmal mehr als 600 MB beträgt, läuft mir immer der Speicher aus.

Ich hoffe, dass ich ein paar Tipps zur Verwaltung der Tabellengröße bekomme, bevor ich sie in die Datenbank einlege, damit ich etwas Speicher freigeben kann, um weiterschreiben zu können.

Hier sind einige Beispiele für meinen Code (einige Spalten und Zeilen wurden der Einfachheit halber weggelassen)

            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());

    }

Ich hatte weiterhin Probleme, SQLBulkCopy zum Laufen zu bringen, und mir wurde klar, dass ich mehr Arbeit an jedem Datensatz machen musste, bevor er in die Datenbank eingegeben wurde. Also entwickelte ich eine einfache Methode von LinQ to Sql, um Aufzeichnungen nach Datensatzaktualisierungen zu machen andere Informationen und erstellt mehr Datensatzinformationen, wie es ausgeführt wurde,

Problem: Diese Methode läuft ziemlich langsam (sogar auf Core i3 Maschine), irgendwelche Ideen, wie man es beschleunigt (Threading?) - auf einem einzigen Prozessorkern, mit 1 GB Speicher stürzt es ab oder dauert manchmal 6-8 Stunden schreibe die gleiche Menge an Daten wie eine SQLBulkCopy, die ein paar Minuten dauert. Es verwaltet jedoch das Gedächtnis besser.

            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();
                    }
                }
            }

Mit Hilfsmethode:

    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();
    }
}

Akzeptierte Antwort

Versuchen Sie, die BatchSize-Eigenschaft auf 1000 festzulegen, wodurch die Einfügung in einer 1000-Datensatz-Charge und nicht in der gesamten Charge durchgeführt wird. Sie können diesen Wert optimieren, um herauszufinden, was optimal ist. Ich habe sqlbulkcopy für Daten ähnlicher Größe verwendet und es funktioniert gut.


Beliebte Antwort

Mit dem gleichen Problem konfrontiert, festgestellt, dass das Problem der OutOfMemory-Ausnahme in DataTable.Rows maximale Mengenbeschränkungen war. Gelöst mit Neuerstellungstabelle, mit maximal 500000 Zeilen Limit. Hoffe, meine Lösung wird hilfreich sein:

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;

    }
}


Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow