2017-01-30 12 views
2

C#.NET 4.0(Visual Studio 2010)、PostgreSQL 9.2、およびNpgsql 2.0.12を使用しています。 Npgsql 3にアップグレードすることはできません。C#とNpgsqlを使用して親テーブルと子テーブルに高速に挿入

親テーブルに高速挿入を行い、その挿入キーの主キーを使用して子テーブルに高速挿入する必要があります。

親テーブルには、プライマリキーである「シリアル」として定義された列があります。

子テーブルには、親テーブルの外部キーである整数列があります。

すべての親レコードに子供がいるわけではありません。親は0,1、または複数の子を持つことができます。

現在、私は親オブジェクトをリストにバッファリングしています。 5000の親がバッファリングされると、レコードをデータベースに書き込むためにスレッドプールから新しいスレッドを生成します。 新しいスレッドは、NpgsqlConnection.BeginTransaction()を呼び出し、ループ内で、親レコードを挿入するパラメータを持つNpgsqlCommand.ExecuteScalar()を呼び出すとともに、親レコードを挿入します。主キーを戻す。 次に、親の子オブジェクトがあればそれを構築し、別のリストに保存します。ループの最後に、親のトランザクションをコミットします。しかし、この方法論は非常に遅いです。どこでも5000レコードを挿入するのに3秒から10秒。確かに良い方法があります。

親がコミットされた後、http://codebetter.com/karlseguin/2009/10/25/postgresql-day-2/(NpgsqlCopyInを使用)で説明されているBulkCopyを使用して、子レコードを挿入します。これは素晴らしい作品です。これは、半秒未満で数千の子レコードを挿入します。

親レコードにもそのBulkCopyを使用したいと思います。しかし、私はどのように一次キー値を一括挿入から戻すのか分かりません。

C#とNpgsqlを使用して、親レコードと子レコードを高速に挿入するにはどうすればよいですか?その答えはおそらくどこかにありますが、明らかに私は正しい検索エンジンのパラメータを使用していません。

ありがとうございます。

答えて

0

serialデータ型を使用すると、Postgresは自動的にシーケンスを生成して割り当てます。これは、あなたが他の目的のためにそのシーケンスをハイジャックすることができるので、これは含まれています。

私の提案です。

あなたのオブジェクトは、次のようになり前提:

public Parent 
{ 
    public long Id { get; set; } 
    public string Description { get; set; } 
    public List<Child> Children { get; set; } 
} 

public Child 
{ 
    public long Id { get; set; } 
    public long ParentId { get; set; } 
    public string Description { get; set; } 
} 

はあなたのコードをお持ちのシーケンスに基づいて、それぞれの親IDを割り当てます。これは、目の点滅で発生する必要があります。

NpgsqlCommand cmd = new NpgsqlCommand("select nextval('schema.foo_id_seq')", conn); 
foreach (Parent p in parentList.Where(x => x.Id == null && x.Id == 0)) 
{ 
    p.Id = Convert.ToInt64(cmd.ExecuteScalar()); 
    p.Children.ForEach(x => x.ParentId = p.Id); 
} 

それらのレコードがすでに存在していない場合は...考えるだけで何かをWhere句が重要となっていない可能性があります。

ここから、あなたのNpgsqlCopyInは、両親と子供のために騒がしいはずです。

+0

ありがとう@Hambone、および入力を提供したすべての人に。このソリューションは完全に機能しました。私はExecuteScalarの呼び出しが 'select nextval ...'を実行しているときの速さに感心しています。乾杯! – TJH

0

この種のシナリオの回答は、通常"hi-lo" key generationのようなものです。要するに、これは、データベースに各挿入物ごとにIDを生成させる代わりに、多数のIDを事前に割り当てて挿入時に指定できるようにすることを意味します。これは、IDを空にしておくのではなく、自分自身でIDを設定していることを意味します(そして、PostgreSQLはそれを許可します)。

具体的には、親テーブルのIDを管理するシーケンスから一群のIDを取得します。詳細はthis questionthis articleを参照してください。次に、アプリケーションにIDを割り当てたら、これらのIDを持つ親を一括して挿入します。

0

私はテキストファイルのディスクに親スクリプトの挿入スクリプトを書いてから、データベースへの1回の往復ですべての親の主キーを返すために通常のコマンドでそれを実行します。

関連する問題