当行依赖于外键值时如何使用BULK INSERT?

13

我的问题与我在ServerFault上提出的问题有关。

基于此,我考虑使用BULK INSERT。我现在明白了,我必须为要保存到数据库中的每个实体准备一个文件。但无论如何,我仍然想知道这个BULK INSERT是否会避免我系统上所描述的内存问题,就像在ServerFault上引用的问题一样。

至于Streets表,它非常简单!我只需要关心两个城市和五个区域作为外键。但是,地址表怎么办?地址表的结构如下:

AddressId int not null identity(1,1) primary key
StreetNumber int null
NumberSuffix_Value int not null DEFAULT 0
StreetId int null references Streets (StreetId)
CityId int not null references Cities (CityId)
SectorId int null references Sectors (SectorId)

如我在ServerFault上所说,我需要插入大约35,000个地址。我应该记住所有的ID吗? =P

然后,现在我需要插入与这些地址相关联的公民人口信息。

PersonId int not null indentity(1,1) primary key
Surname nvarchar not null
FirstName nvarchar not null
IsActive bit
AddressId int null references Addresses (AddressId)

我能想到的唯一办法就是强制将ID设置为静态值,但这样一来,我就失去了以前用“INSERT..SELECT”策略所拥有的任何灵活性。
那么我的选择是什么?
  1. 我强制将ID始终设置为相同的值,然后我必须使用SET IDENTITY_INSERT ON来强制将值插入表中,这样每行的ID都是相同的,正如此处所建议的那样。
  2. 如何使用外键进行批量插入?我无法在任何地方找到相关文档。=(
感谢您的帮助!
编辑:
我编辑了以包含BULK INSERT SQL指令,最终成功了!
我已经准备好要插入的Excel工作簿信息。所以,我只需创建一些辅助工作表,并开始编写公式,以便将信息数据“导入”到这些新工作表中。我为我的每个实体都创建了一个工作表:
  1. 街道;
  2. 地址;
  3. 公民。

至于另外两个实体,它们不值得批量插入,因为我只有两个城市和五个部门(城市细分)需要插入。一旦城市和部门都插入完成,我就记录了它们各自的ID,并准备好了批量插入的记录集。顺便说一下,使用Excel计算值并“导入”外键是一个很好的方法。之后,我将每个工作表保存到单独的CSV文件中。我的记录现在已经准备好批量处理了。

USE [DatabaseName]
GO

delete from Citizens
delete from Addresses
delete from Streets

BULK INSERT Streets
    FROM N'C:\SomeFolder\SomeSubfolder\Streets.csv'
    WITH (
        FIRSTROW = 2
        , KEEPIDENTITY
        , FIELDTERMINATOR = N','
        , ROWTERMINATOR = N'\n'
        , CODEPAGE = N'ACP'
    )
GO
  • FIRSTROW

    表示开始插入的行号。在我的情况下,我的CSV文件包含了列标题,因此第二行是应该开始的行。除此之外,你可能想从文件的任意位置开始,比如第15行。

  • KEEPIDENTITY

    允许批量插入指定的实体ID,即使表中有自增列。这个参数与在插入行时使用SET INDENTITY_INSERT my_table ON来精确插入ID是相同的。

至于其他参数,它们本身就很清楚了。

现在这个代码对于剩下的两个实体——地址和公民——进行了重复。由于指定了KEEPIDENTITY,所有的外键都保持不变,尽管我的主键在SQL Server中被设置为自增列。

只需要做一些微调,就像marc_s在他的回答中所说的那样,尽可能快地将数据导入到一个没有任何限制的临时表中。这样,你会更轻松地完成任务,同时仍然遵循良好的实践。=)

1个回答

20

基本思想是将数据批量插入到一个没有任何限制、约束等的临时表中,尽可能快地完成数据的批量加载。

一旦你将数据加载到临时表中,然后你需要开始关注插入数据到真实表时的约束等问题。

在这里,你可以:

  • 仅将符合所有条件的行插入到你的真实工作表中,并在你的临时表中标记它们为“成功插入”

  • 处理剩余未被成功插入的所有行,可能需要进行错误/恢复处理 – 例如:打印所有“问题”行的报告、将它们放入“错误存储”中等等。这完全取决于你。

关键点是:实际的BULK INSERT应该是在一个完全没有约束的表中 – 只需尽可能快地加载数据 – 然后再在第二步中开始关注约束、查找数据、引用等问题。


2
我们的应用程序使用这种策略一次性加载数百万行。 - DaveE
2
这很有道理。一旦插入数据行,它们就会更容易操作。感谢你的建议,Marc!=) - Will Marcouiller
2
我终于成功地批量插入了成千上万行数据!至于外键,有一个特殊的参数KEEPIDENTITY,因此可以在CSV文件中指定外键值,并期望插入这些外键值。 - Will Marcouiller

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接