2

異なるマシンで2台のSQL2008サーバーを使用しています。サーバー名は、、source.ex.comおよびdestination.ex.comです。

destination.ex.comにリンクされており、呼び出され たデータベースに書き込むsource.ex.comための適切な権限が設定されています。source.ex.combacon-wrenchdestination.ex.com

source.ex.comSMS経由でログインし、このクエリをテストしました(正常に):

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

C#.NET 4.0 Webページで、接続し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:以下のメッセージは私が修正しようとしているものです:

Webページがクラッシュしbulk.WriteToServer(dt);てエラーメッセージが表示されますDatabase bacon-wrench does not exist please ensure it is typed correctly.何が間違っていますか?これを変更して機能させるにはどうすればよいですか?

編集1:

以下の構文を使用して、クエリを大幅に高速化することができました。しかし、そのような小さなレコードセットではまだ非常に遅いです。

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

2 に答える 2

1

SQL Server 2008 以降を使用している場合は、テーブル ユーザー データ型を導入できます。以下のような型、受け取りテーブル、ストアドプロシージャを用意します。データ型とストアド プロシージャはローカル システムにあります。通常、テーブルがリモートかローカルかを検出するコードに 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();
}
于 2016-06-06T21:22:58.837 に答える
0

リンク サーバーの設定、照合順序、類義語など、さまざまなことを試した後、最終的に次のエラー メッセージが表示されました。

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

おそらく、ローカル サーバー上のステージング テーブルに一括挿入し (コードはこれに対して正常に動作します)、そのステージング テーブルからリンク サーバーに挿入し、その後、ステージング テーブルをローカルで削除することができます。パフォーマンスをテストする必要があります。

于 2013-01-25T22:24:12.350 に答える