2013-01-25 2 views
2

Я работаю с 2 серверами SQL 2008 на разных машинах. Имена серверов: source.ex.com и destination.ex.com.SqlBulkInsert с DataTable на связанный сервер

destination.ex.com связан с source.ex.com и соответствующими разрешениями на месте для source.ex.com записи в базу данных под названием bacon-wrench на destination.ex.com

Я вошедший в source.ex.com с помощью SMS и тестировал этот запрос (успешно):

INSERT INTO [destination.ex.com].[bacon-wrench].[dbo].[tblFruitPunch] 
(PunchID, BaconID) VALUES (4,6); 

в C# .NET 4.0 WebPage я подключиться к source.ex.com и выполнить аналогичный запрос (успешно):

using(SqlConnection c = new SqlConnection(ConfigurationManager.ConnectionStrings["SOURCE"].ConnectionString)) 
{ 
    c.Open(); 
    String sql = @" 
     INSERT INTO [destination.ex.com].[bacon-wrench].[dbo].[tblFruitPunch] 
     (PunchID, BaconID) VALUES (34,56);"; 
    using(SqlCommand cmd = new SqlCommand(sql, c)) 
    { 
     cmd.ExecuteNonQuery(); 
    } 
} 

Для небольших наборов утверждений вставки (скажем, 20 или меньше) делает что-то вроде этого выполняет отлично:

using(SqlConnection c = new SqlConnection(ConfigurationManager.ConnectionStrings["SOURCE"].ConnectionString)) 
{ 
    c.Open(); 
    String sql = @" 
     INSERT INTO [destination.ex.com].[bacon-wrench].[dbo].[tblFruitPunch] 
     (PunchID, BaconID) VALUES (34,56); 
     INSERT INTO [destination.ex.com].[bacon-wrench].[dbo].[tblFruitPunch] 
     (PunchID, BaconID) VALUES (22,11); 
     INSERT INTO [destination.ex.com].[bacon-wrench].[dbo].[tblFruitPunch] 
     (PunchID, BaconID) VALUES (33,55); 
     INSERT INTO [destination.ex.com].[bacon-wrench].[dbo].[tblFruitPunch] 
     (PunchID, BaconID) VALUES (1,2);"; 
    using(SqlCommand cmd = new SqlCommand(sql, c)) 
    { 
     cmd.ExecuteNonQuery(); 
    } 
} 

Я пытаюсь сделать что-то вроде этого с около 20000 записей. Вышеуказанный метод занимает 11 минут, чтобы завершить, что, я полагаю, является сервером, который навязывает мне, чтобы сделать его какой-то объемной операцией. Из других потоков StackOverflow был рекомендован класс SqlBulkCopy, и он принимает в качестве параметра DataTable, отлично!

Так что я построить DataTable и попытаться записать его на сервер (обязательно):

DataTable dt = new DataTable(); 
dt.Columns.Add("PunchID", typeof(int)); 
dt.Columns.Add("BaconID", typeof(int)); 
for(int i = 0; i < 20000; i++) 
{ 
    //I realize this would make 20000 duplicate 
    //rows but its not important 
    dt.Rows.Add(new object[] { 
     11, 33 
    }); 
} 

using(SqlConnection c = new SqlConnection(ConfigurationManager.ConnectionStrings["SOURCE"].ConnectionString)) 
{ 
    c.Open(); 
    using(SqlBulkCopy bulk = new SqlBulkCopy(c)) 
    { 
     bulk.DestinationTableName = "[destination.ex.com].[bacon-wrench].[dbo].[tblFruitPunch]"; 
     bulk.ColumnMappings.Add("PunchID", "PunchID"); 
     bulk.ColumnMappings.Add("BaconID", "BaconID"); 
     bulk.WriteToServer(dt); 
    } 
} 

edit2: Ниже сообщение, что я пытаюсь исправить:

веб-страница аварий на bulk.WriteToServer(dt); с сообщением об ошибке Database bacon-wrench does not exist please ensure it is typed correctly. Что я делаю неправильно? Как изменить это, чтобы заставить его работать?

EDIT1:

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

using(SqlConnection c = new SqlConnection(ConfigurationManager.ConnectionStrings["SOURCE"].ConnectionString)) 
{ 
    c.Open(); 
    String sql = @" 
     INSERT INTO [destination.ex.com].[bacon-wrench].[dbo].[tblFruitPunch] 
     (PunchID, BaconID) VALUES 
     (34,56), 
     (22,11), 
     (33,55), 
     (1,2);"; 
    using(SqlCommand cmd = new SqlCommand(sql, c)) 
    { 
     cmd.ExecuteNonQuery(); 
    } 
} 

ответ

0

Перепробовав ряд вещей, в том числе связанных с настройками сервера сортировки, синонимов и т.д., я в конце концов получил это сообщение об ошибке:

Inserting into remote tables or views is not allowed by using the BCP utility or by using BULK INSERT.

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

+0

Oh Noes! Я попробую, как вы предложили. –

0

Если вы используете SQL Server 2008+, вы можете ввести тип данных пользователя Table. Подготовьте тип, таблицу приема и хранимую процедуру, как показано ниже. Тип данных и хранимая процедура находятся в локальной системе. Обычно у меня есть оператор if в коде, определяющем, является ли таблица удаленной или локальной, удаленной я делаю это, локальный я использую SqlBulkCopy.

if(TYPE_ID(N'[Owner].[TempTableType]') is null) 
begin 
CREATE TYPE [Owner].[TempTableType] AS TABLE ([PendingID] uniqueidentifier, [Reject] bit) 
end 
IF NOT EXISTS (SELECT * FROM [LinkedServer].[DatabaseOnLS].sys.tables where name = 'TableToReceive') 
EXEC(' 
CREATE TABLE [DatabaseOnLS].[Owner].[TableToReceive] ([PendingID] uniqueidentifier, [Reject] bit) 
') AT [LinkedServer] 
else 
EXEC(' 
TRUNCATE TABLE [DatabaseOnLS].[Owner].[TableToReceive] 
') AT [LinkedServer] 

CREATE PROCEDURE [Owner].[TempInsertTable] 
@newTableType TempTableType readonly 
AS 
BEGIN 
insert into [LinkedServer].[DatabaseOnLS].[Owner].[TableToReceive] select * from @newTableType 
END 

В коде C#, то вы можете сделать что-то вроде этого, чтобы вставить DataTable в таблицу на связанном сервере (я использую существующий UnitOfWork, которые уже имеют связи и сделки):

using (var command = new SqlCommand("TempInsertTable", 
        oUoW.Database.Connection as SqlConnection) { CommandType = CommandType.StoredProcedure } 
       ) 
{ 
    command.Transaction = oUoW.Database.CurrentTransaction as SqlTransaction; 
    command.Parameters.Add(new SqlParameter("@newTableType", oTempTable)); 
    drResults = command.ExecuteReader(); 
    drResults.Close(); 
} 
Смежные вопросы