7

C# 経由で一括データをロードする最速の方法を探しています。仕事はしますが遅いこのスクリプトがあります。SqlBulkCopy が最速であるという証言を読みました。
1000 レコード 2.5 秒。ファイルには 5000 から 250k 近くのレコードが含まれています。

テーブル定義:

CREATE TABLE [dbo].[tempDispositions](
    [QuotaGroup] [varchar](100) NULL,
    [Country] [varchar](50) NULL,
    [ServiceGroup] [varchar](50) NULL,
    [Language] [varchar](50) NULL,
    [ContactChannel] [varchar](10) NULL,
    [TrackingID] [varchar](20) NULL,
    [CaseClosedDate] [varchar](25) NULL,
    [MSFTRep] [varchar](50) NULL,
    [CustEmail] [varchar](100) NULL,
    [CustPhone] [varchar](100) NULL,
    [CustomerName] [nvarchar](100) NULL,
    [ProductFamily] [varchar](35) NULL,
    [ProductSubType] [varchar](255) NULL,
    [CandidateReceivedDate] [varchar](25) NULL,
    [SurveyMode] [varchar](1) NULL,
    [SurveyWaveStartDate] [varchar](25) NULL,
    [SurveyInvitationDate] [varchar](25) NULL,
    [SurveyReminderDate] [varchar](25) NULL,
    [SurveyCompleteDate] [varchar](25) NULL,
    [OptOutDate] [varchar](25) NULL,
    [SurveyWaveEndDate] [varchar](25) NULL,
    [DispositionCode] [varchar](5) NULL,
    [SurveyName] [varchar](20) NULL,
    [SurveyVendor] [varchar](20) NULL,
    [BusinessUnitName] [varchar](25) NULL,
    [UploadId] [int] NULL,
    [LineNumber] [int] NULL,
    [BusinessUnitSubgroup] [varchar](25) NULL,
    [FileDate] [datetime] NULL
) ON [PRIMARY]

そしてここにコードがあります

    private void BulkLoadContent(DataTable dt)
    {
        OnMessage("Bulk loading records to temp table");
        OnSubMessage("Bulk Load Started");
        using (SqlBulkCopy bcp = new SqlBulkCopy(conn))
        {
            bcp.DestinationTableName = "dbo.tempDispositions";
            bcp.BulkCopyTimeout = 0;
            foreach (DataColumn dc in dt.Columns)
            {
                bcp.ColumnMappings.Add(dc.ColumnName, dc.ColumnName);
            }
            bcp.NotifyAfter = 2000;
            bcp.SqlRowsCopied += new SqlRowsCopiedEventHandler(bcp_SqlRowsCopied);
            bcp.WriteToServer(dt);
            bcp.Close();
        }
    }
4

7 に答える 7

8

そのテーブルにインデックス、トリガー、または制約がありますか?

これにより、挿入が遅くなります。特に、クラスター化されたインデックスが問題になります。実行しているデータの量を増やすときは、最初にインデックスを削除し、後で再適用するのが最善です。

それについての良い投稿はここにあります: SQL Server(C#クライアント)に大量のデータを一括挿入するための最速の方法は何ですか

于 2010-04-22T16:49:13.480 に答える
4

大量のデータがある場合は、batchsize をかなり大きな数に設定すると役立つ場合があります。

bcp.BatchSize = 10000;
于 2011-03-30T13:44:25.807 に答える
1

一括コピーを遅くする可能性があるもの: - テーブルのフル テキスト インデックス - 挿入時のトリガー - 外部キー制約

于 2010-04-22T16:51:05.190 に答える
1

大規模なデータセットをフラッシュしようとすると、最初ははるかに高速ですが、時間の経過とともに大幅に遅くなることに気付きました。私は、バッファリングされたアプローチを使用してパフォーマンスがわずかに向上し、同じ接続で一度に数千のレコードを一括コピーすることを発見しました。バッチごとのトランザクション時間を時間の経過とともに抑えるように思われるため、(時間の経過とともに) パフォーマンスが向上します。私のソリューションでは、バッファリングされていない同じメソッドは、このメソッドが同じタイプの約 7,500,000 レコードを同じ DB に保存するのにかかる時間で約 5,000,000 レコードを保存することに気付きました。これが誰かに役立つことを願っています。

public void flush_DataTable(DataTable dt, string tableName)//my incoming DTs have a million or so each and slow down over time to nothing. This helps.
    {  int bufferSize = 10000;
        int bufferHigh = bufferSize;
        int lowBuffer = 0;
        if (dt.Rows.Count >= bufferSize)
        {  using (SqlConnection conn = getConn())
            {   conn.Open();
                while (bufferHigh < dt.Rows.Count)
                {
                    using (SqlBulkCopy s = new SqlBulkCopy(conn))
                    {   s.BulkCopyTimeout = 900;
                        s.DestinationTableName = tableName;
                        s.BatchSize = bufferSize;

                        s.EnableStreaming = true;
                        foreach (var column in dt.Columns)
                            s.ColumnMappings.Add(column.ToString(), column.ToString());
                        DataTable bufferedTable = dt.Clone();
                        for (int bu = lowBuffer; bu < bufferHigh; bu++)
                        {
                            bufferedTable.ImportRow(dt.Rows[bu]);
                        }
                        s.WriteToServer(bufferedTable);
                        if (bufferHigh == dt.Rows.Count)
                        {
                            break;
                        }
                        lowBuffer = bufferHigh;
                        bufferHigh += bufferSize;

                        if (bufferHigh > dt.Rows.Count)
                        {
                            bufferHigh = dt.Rows.Count;
                        }
                    }
                }
                conn.Close();
            }
        }
        else
        {
            flushDataTable(dt, tableName);//perofrm a non-buffered flush (could just as easily flush the buffer here bu I already had the other method 
        }
    }
于 2016-08-08T11:38:56.653 に答える
0

ここで提案した IDataReader の実装 IDataReaderを実装するにはどうすればよいですか? たぶんあなたを助けます。次のように SqlBulkCopy で使用しました。

using (MyFileDataReader reader = new MyFileDataReader(@"C:\myfile.txt"))
 {
      SqlBulkCopy bulkCopy = new SqlBulkCopy(connection);
      bulkCopy.DestinationTableName = "[my_table]";
      bulkCopy.BatchSize = 10000;

      bulkCopy.WriteToServer(reader);

      bulkCopy.Close();

 } 
于 2013-05-22T15:57:47.963 に答える
0

私も似たような経験をしたばかりです。 SqlBulkCopyあるテーブルでは問題ありませんでしたが、別のテーブルでは、同じ数のレコードをコピーするのに少なくとも 10 倍遅くなりました。

遅いテーブルには非クラスター化インデックスとトリガーがありましたが、それらを無効にしても大きな違いはありませんでした。

遅いテーブルには 6 つのNVARCHAR(MAX)列があることがわかりました。実際に挿入していたデータはすべてかなり短いので、列を に変更しましたNVARCHAR(500)

ほら!遅いテーブルのパフォーマンスは、他のテーブルと一致するように改善されました。少なくとも 10 倍の速度向上です。

于 2022-02-17T11:39:38.253 に答える