Подтвердить что ты не робот

Каков наилучший способ вставки больших баз данных из С#?

Как я/что лучший способ делать массовые вставки базы данных?

В С# я выполняю итерацию по коллекции и вызываю хранимую процедуру вставки для каждого элемента в коллекции.

Как отправить все данные в один вызов базы данных?

например. У меня есть список людей (List<Person>), содержащий 10 элементов. В настоящее время я вызываю файл InsertPerson 10 раз. Я хотел бы уменьшить это до 1 вызова.

Я использую MS SQL Server 2005.

4b9b3361

Ответ 1

CsharperGuyInLondon, вот простой пример кода SqlBulkCopy:

using System.Data.SqlClient;

DataTable table = new DataTable("States");
// construct DataTable
table.Columns.Add(new DataColumn("id_state", typeof(int))); 
table.Columns.Add(new DataColumn("state_name", typeof(string)));

// note: if "id_state" is defined as an identity column in your DB,
// row values for that column will be ignored during the bulk copy
table.Rows.Add("1", "Atlanta");
table.Rows.Add("2", "Chicago");
table.Rows.Add("3", "Springfield");

using(SqlBulkCopy bulkCopy = new SqlBulkCopy(connectionString))
{
  bulkCopy.BulkCopyTimeout = 600; // in seconds
  bulkCopy.DestinationTableName = "state";
  bulkCopy.WriteToServer(table);
}

Ответ 2

Ну, 10 предметов - это не то, что я называю массовым, но для больших наборов SqlBulkCopy - ваш друг. Все, что вам нужно сделать, это подать его либо DataTable, либо IDataReader (мой предпочтительный вариант, потому что мне нравится потоковое API). Я сделал что-то подобное здесь (вы можете игнорировать сторону xml - просто подкласс SimpleDataReader).

Ответ 3

Класс .NET SqlBulkCopy работает очень хорошо.

Ответ 4

Вы можете создать BLOB (изображение) и отправить его в качестве параметра хранимой процедуры. Внутри хранимой процедуры вы можете получить все элементы, используя substring().

Ответ 6

Я создаю список как строку xml и передаю его в сохраненный proc. В SQL 2005 у него есть расширенные функциональные возможности xml для синтаксического анализа xml и выполнения объемной вставки.

проверить этот пост: Передача списков SQL Server 2005 с параметрами XML

Ответ 7

Сбросьте свои данные в ограничиваемый канал (или что-то еще, если ваши данные имеют в нем каналы), и используйте Bulk Insert.

Ответ 8

Вы можете обновить документ Xml, Sql 2005 отлично работает с ними. Один node для каждой строки, но только один параметр для Xml.

Ответ 9

Создайте XML-документ, содержащий все элементы, которые нужно вставить. Затем внутри хранимой процедуры используйте поддержку TSQL xml (OPENXML), чтобы прочитать все данные из документа XML и вставить его в свои таблицы с надеждой один оператор insert для каждой таблицы.

Однако, если вы только вставляете данные в одну таблицу и не нуждаетесь в логике на стороне базы данных, почему бы не использовать SqlBulkCopy?

Ответ 10

Верно решение для SqlBulkCopy, я создал класс, чем принимает Datatable или List<T> и размер буфера (CommitBatchSize). Он преобразует список в таблицу данных с использованием расширения (во втором классе).

Он работает очень быстро. На моем ПК я могу вставить более 10 миллионов сложных записей менее чем за 10 секунд.

Вот класс:

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DAL
{

public class BulkUploadToSql<T>
{
    public IList<T> InternalStore { get; set; }
    public string TableName { get; set; }
    public int CommitBatchSize { get; set; }=1000;
    public string ConnectionString { get; set; }

    public void Commit()
    {
        if (InternalStore.Count>0)
        {
            DataTable dt;
            int numberOfPages = (InternalStore.Count / CommitBatchSize)  + (InternalStore.Count % CommitBatchSize == 0 ? 0 : 1);
            for (int pageIndex = 0; pageIndex < numberOfPages; pageIndex++)
                {
                    dt= InternalStore.Skip(pageIndex * CommitBatchSize).Take(CommitBatchSize).ToDataTable();
                BulkInsert(dt);
                }
        } 
    }

    public void BulkInsert(DataTable dt)
    {
        using (SqlConnection connection = new SqlConnection(ConnectionString))
        {
            // make sure to enable triggers
            // more on triggers in next post
            SqlBulkCopy bulkCopy =
                new SqlBulkCopy
                (
                connection,
                SqlBulkCopyOptions.TableLock |
                SqlBulkCopyOptions.FireTriggers |
                SqlBulkCopyOptions.UseInternalTransaction,
                null
                );

            // set the destination table name
            bulkCopy.DestinationTableName = TableName;
            connection.Open();

            // write the data in the "dataTable"
            bulkCopy.WriteToServer(dt);
            connection.Close();
        }
        // reset
        //this.dataTable.Clear();
    }

}

public static class BulkUploadToSqlHelper
{
    public static DataTable ToDataTable<T>(this IEnumerable<T> data)
    {
        PropertyDescriptorCollection properties =
            TypeDescriptor.GetProperties(typeof(T));
        DataTable table = new DataTable();
        foreach (PropertyDescriptor prop in properties)
            table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
        foreach (T item in data)
        {
            DataRow row = table.NewRow();
            foreach (PropertyDescriptor prop in properties)
                row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
            table.Rows.Add(row);
        }
        return table;
    }
}

}

Вот пример, когда я хочу вставить список моего пользовательского объекта List<PuckDetection> (ListDetections):

var objBulk = new BulkUploadToSql<PuckDetection>()
{
        InternalStore = ListDetections,
        TableName= "PuckDetections",
        CommitBatchSize=1000,
        ConnectionString="ENTER YOU CONNECTION STRING"
};
objBulk.Commit();