繁体   English   中英

使用C#和Npgsql快速插入父表和子表

[英]Fast insert into parent and child tables using C# and Npgsql

我正在使用C#.NET 4.0(Visual Studio 2010),PostgreSQL 9.2和Npgsql 2.0.12。 我无法升级到Npgsql 3。

我需要在父表中进行快速插入,然后使用该插入中的主键在子表中进行快速插入。

父表有一个定义为“ serial”的列,它是主键。

子表具有一个整数列,该整数列是返回到父表的外键。

并非每个父母记录都会有孩子。 父母可以有0个,1个或多个孩子。

目前,我正在将父对象缓冲到列表中。 缓冲了5000个父级后,请从线程池中生成一个新线程,以将记录写入数据库。 (为主线程创建了一个新的列表,以缓冲下一组父对象。)新线程调用NpgsqlConnection.BeginTransaction(),然后在循环内调用NpgsqlCommand.ExecuteScalar(),并带有参数以插入父记录并获取父记录。主键返回。 然后构建父对象的子对象(如果有)并保存到另一个列表。 在循环结束时,提交父母的交易。 但是这种方法太慢了。 从3到10秒的任何时间插入5000条记录。 当然有更好的方法。

提交父项后,我使用http://codebetter.com/karlseguin/2009/10/25/postgresql-day-2/ (使用NpgsqlCopyIn)中介绍的BulkCopy插入子项记录。 这很神奇。 它在不到半秒钟的时间内插入了数千条子记录。

我也想将BulkCopy用于父记录。 但是我不知道如何从批量插入中获取主键值。

那么,使用C#和Npgsql快速插入父子记录的诀窍是什么? 答案可能在某个地方,但是显然我没有使用正确的搜索引擎参数。

首先十分感谢。

这种情况的答案通常类似于“ hi-lo”密钥生成 简而言之,这意味着您可以预先分配大量的ID并在插入时指定它们,而不是让数据库在每个插入中都生成ID(强制您确实检索这些ID)。 这意味着您要自己在每个父级上设置ID,而不是将其保留为空(并让PostgreSQL执行)。

具体而言,您将从管理父表ID的序列中检索一批ID-有关更多信息,请参阅此问题本文 然后,一旦您的应用程序中包含了ID,就可以批量插入带有这些ID的父母。

我将父母插入脚本写到文本文件中的磁盘上,然后通过常规命令运行该脚本,以在一次往返数据库的操作中取回所有父母主键。

当您使用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; }
}

让您的代码根据顺序为每个Parent分配一个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应该对父母和孩子都适用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM