2015-03-23 3 views
0

У меня есть инструмент, который вставляет/обновляет тысячи записей в час в базе данных. Она считывает ввод в dataTable и запускает команду SQL строка за строкой:Быстрый способ вставки записей в SQL db

for(int i = 0; i < dataTable.Rows.Count; i++) 
{ 
    string sqlConnectionString = "server, db, user, pass, etc."; 
    SqlConnection sqlDBConnection = new SqlConnection(sqlConnectionString); 

    string query = @"INSERT INTO table 
        (col1, col2, col3, etc.) 
        VALUES 
        (@col1, @col2, @col3, etc.)"; 
    SqlCommand queryCommand = new SqlCommand(query, sqlDBConnection); 

    queryCommand.Parameters.Add("@col1", SqlDbType.Int); 
    queryCommand.Parameters["@col1"].Value = Convert.ToInt32(dataTable.Rows[i][0]); 

    queryCommand.Parameters.Add("@col2", SqlDbType.VarChar); 
    queryCommand.Parameters["@col2"].Value = dataTable.Rows[i][1].ToString(); 

    queryCommand.Parameters.Add("@col3", SqlDbType.VarChar); 
    queryCommand.Parameters["@col3"].Value = dataTable.Rows[i][2].ToString(); 

    sqlDBConnection.Open(); 
    queryCommand.ExecuteNonQuery(); 
    sqlDBConnection.Close(); 
} 

Это прекрасно работает, но это очень медленный процесс. У вас есть более быстрое решение?

+0

Не отсоединяйте/подключайте для каждой вставки. Группа вставляет вместе в более крупные транзакции и т. Д. – jarlh

ответ

1

Поскольку ваши данные уже находятся в DataTable, я думаю, что лучший способ - использовать SQLBulkCopy. например

string sqlConnectionString = "server, db, user, pass, etc."; 
using (var bulkCopy = new SqlBulkCopy(sqlConnectionString)) 
{ 
    bulkCopy.DestinationTableName = "table"; 
    bulkCopy.ColumnMappings.Add("Col1", "Col1"); 
    bulkCopy.ColumnMappings.Add("Col2", "Col2"); 
    bulkCopy.ColumnMappings.Add("Col3", "Col3"); 
    bulkCopy.WriteToServer(dataTable); 
} 

Для обновления существующих записей, если вы заполнили ваш DataTable с помощью SqlDataAdapter вы можете использовать метод SqlDataAdapter.Update(). Если нет, то я бы рекомендовал обработать upsert в SQL. Поскольку вы используете SQL Server 2012, вы можете использовать параметр Table Valued Parameter. Первый шаг заключается в создании вашего Table type

CREATE TYPE dbo.YourTableType TABLE 
(
    Col1 INT, 
    Col2 INT, 
    Col3 INT 
); 

Это должно иметь такое же определение, как ваш C# DataTable.

Тогда следующий шаг должен был бы создать хранимую процедуру, которая принимает этот тип в качестве параметра, и использует MERGE для вставки или обновления записей в зависимости от того, есть или нет матч:

CREATE PROCEDURE dbo.UpsertYourTable @Table dbo.YourTableType READONLY 
AS 
BEGIN 
    MERGE dbo.YourTable WITH (HOLDLOCK) AS t 
    USING @Table AS s 
     ON s.Col1 = t.Col1 -- OR HOWEVER YOU IDENTIFY EXISTING RECORDS 
    WHEN MATCHED THEN UPDATE 
     SET Col2 = Col2, 
      Col3 = Col4 
    WHEN NOT MATCHED THEN 
     INSERT (Col1, Col2, Col3, Col4) 
     VALUES (s.Col1, s.Col2, s.Col3, 'Test'); 

END; 
GO 

Наконец, в назовите это c C#, которое вы использовали бы:

string sqlConnectionString = "server, db, user, pass, etc."; 
using (var connection = new SqlConnection(sqlConnectionString)) 
using (var command = new SqlCommand("dbo.UpsertYourTable", connection)) 
{ 
    command.CommandType = CommandType.StoredProcedure; 
    var tvp = new SqlParameter("@Table", SqlDbType.Structured); 
    tvp.Value = dataTable; 
    tvp.TypeName = "dbo.YourTableType"; 
    command.Parameters.Add(tvp); 
    command.ExecuteNonQuery(); 
} 
+0

Это выглядит хорошо. Вы знаете, как ускорить обновление существующих записей? – fishmong3r

+0

Также возможно не использовать, например. col2, но предположим, что данная строка в col2 называется «test»? – fishmong3r

+0

Вам не придется добавлять этот столбец в свой DataTable. Какую версию SQL Server вы используете? – GarethD

1

Используйте либо массовую вставку с SqlBulkCopy Class, либо Table Valued Parameters in C#.
Это должно ускорить работу до

+0

+1 на этом, объемная копия SQL на сегодняшний день является самым быстрым способом, если у вас есть схема, и вы можете генерировать идентификаторы поэтапно самостоятельно. Я лично сделал 20 000 строк в секунду для увеличения копия. Вот пример, который может быть полезен: http://www.codeproject.com/Articles/18418/Transferring-Data-Using-SqlBulkCopy – finman

0

Это медленный процесс, потому что каждая вставка сама по себе, что вызывает накладные расходы на время транзакции. Попробуйте сделать объемную вставку с помощью различных методов. Будь на фреймворк (например, весенний объем) или просто изменив свой запрос, чтобы вставить несколько значений за один снимок.

insert into table (col1, col2, col3, ...) 
values   (val1, val2, cal3, ...), 
        (val1, val2, cal3, ...), 
        (val1, val2, cal3, ...), ... 

но не конкатенируйте все из них, чтобы не задерживать буферизацию db-соединения.

0

Вы занимались с SSIS? или через Bulk Insert. Независимо от того, какой вариант вы выберете, вы хотите свести к минимуму количество подключений, идущих к вызову db, один раз в несколько тысяч раз будет интенсивным.

Смежные вопросы