2017-01-30 33 views
2

我使用C#.NET 4.0(Visual Studio 2010中)和PostgreSQL 9.2和2.0.12 Npgsql的父和子表。我無法升級到Npgsql 3.我需要快速插入到父表中,然後使用該插入的主鍵,快速插入到子表中。快速插入到使用C#和Npgsql的

父表具有被定義爲「串行」即是主鍵的列。

子表有一個整數列,它是一個外鍵回父表。

不是每個父母記錄都會有孩子。父母可以有0,1或許多孩子。

目前我正在緩衝父對象的列表。當5000個父母被緩衝後,從線程池產生一個新線程將記錄寫入數據庫。 (爲主線程創建一個新的列表 ,以緩衝下一組父對象。) 新線程調用NpgsqlConnection.BeginTransaction(),然後在一個循環內調用帶有參數的NpgsqlCommand.ExecuteScalar()以插入父記錄並取回主鍵。 然後構建父級的子對象(如果有)並保存到另一個List。在循環結束時提交父母的交易。但是這種方法很慢。從3到10秒的任何地方插入5000條記錄。當然有更好的方法。

父母犯下後,我使用BulkCopy http://codebetter.com/karlseguin/2009/10/25/postgresql-day-2/(使用NpgsqlCopyIn)插入子記錄。這工作很棒。它在不到半秒的時間內插入數千個兒童記錄。

我喜歡使用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,並感謝所有提供意見的人。此解決方案完美運作。我剛剛做了'select nextval ...'時,對ExecuteScalar的調用速度有多快讓我印象深刻。乾杯! – TJH

0

爲這種情況的答案通常是這樣的"hi-lo" key generation。簡而言之,這意味着不必讓每個插入數據庫都生成ID(強制您檢索這些ID),您可以預先分配大量ID並在插入時指定它們。這意味着你要在每個父母身上設置ID,而不是將它留空(並讓PostgreSQL去做)。

具體而言,您將從管理父表ID的序列中檢索一批ID - 有關更多信息,請參閱this questionthis article。然後,一旦在應用程序中有了這些ID,就可以批量插入這些ID的父母。

0

我會寫父母插入腳本到磁盤的文本文件,然後運行它通過一個常規的命令來取回所有的父母主鍵在數據庫的往返旅程。