如何使用SQL Server中的DataTable模拟“批量”插入
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用SQL Server中的DataTable模拟“批量”插入相关的知识,希望对你有一定的参考价值。
我有一个存储过程,我发送一个用户定义的类型,这是一个表。我已经简化了以便于阅读。
CREATE TYPE [dbo].[ProjectTableType] AS TABLE(
[DbId] [uniqueidentifier] NOT NULL,
[DbParentId] [uniqueidentifier] NULL,
[Description] [text] NULL
)
CREATE PROCEDURE [dbo].[udsp_ProjectDUI] (@cmd varchar(10),
@tblProjects ProjectTableType READONLY) AS BEGIN
DECLARE @myNewPKTable TABLE (myNewPK uniqueidentifier)
IF(LOWER(@cmd) = 'insert')
BEGIN
INSERT INTO
dbo.Project
(
DbId,
DbParentId,
Description)
OUTPUT INSERTED.DbId INTO @myNewPKTable
SELECT NEWID(),
DbParentId,
Description
FROM @tblProjects;
SELECT * FROM dbo.Project WHERE dbid IN (SELECT myNewPK FROM @myNewPKTable);
END
这适用于其他应用程序将使用的DLL,因此我们不必对验证负责。我想模仿BULK INSERT,如果一行无法插入但其他行都很好,那么正确的行仍会插入。有没有办法做到这一点?我想为UPDATE做这个,如果一个失败,存储过程将继续尝试更新其他的。
我能想到的唯一选择是一次只执行一个(在代码中循环多次调用存储过程的循环或存储过程中的循环),但是想知道性能的影响是什么或者如果有更好的解决方案。
不确定你想要继续哪些错误,但除非你遇到各种意外错误,否则我会尽量避免转入RBAR。
检查明确的违规行为
我认为主要的是PK挥发,你可以通过在插入(和更新)之前检查存在来避免。如果还有其他业务逻辑故障情况,您也可以在此处查看。
insert into dbo.Project
(
DbId,
DbParentId,
Description
)
output insert.DbId
into @myNewPKTable (DbId)
select
DbId = newid(),
DbParentId = s.DbParentId,
Description = s.Description
from @tblProjects s -- source
-- LOJ null check makes sure we don't violate PK
-- NOTE: I'm pretending this is an alternate key of the table.
left outer join dbo.Project t -- target
on s.dbParentId = t.dbParentId
where t.dbParentId is null
如果可能的话,我会尝试坚持批量更新,并使用连接谓词来消除您期望看到的大多数错误的可能性。更改为RBAR处理因为您担心“可能”会导致系统关闭失败,这可能是浪费时间。然后,如果你遇到一个非常讨厌的错误,你无法恢复,合法地失败批处理。
橡胶
或者,如果您绝对需要逐行的成功或失败粒度,您可以尝试/捕获每个语句并让catch块不执行任何操作(或记录某些内容)。
declare
@DBParentId int,
@Description nvarchar(1000),
@Ident int
declare c cursor local fast_forward for
select
DbParentId = s.DbParentId,
Description = s.Description
from @tblProjects
open c
fetch next from c into @DBParentId, @Description
while @@fetch_status = 0
begin
begin try
insert into dbo.Project
(
DbId,
DbParentId,
Description
)
output insert.DbId
into @myNewPKTable (DbId)
select
newid(),
@DBParentId,
@Description
end try
begin catch
-- log something if you want
print error_message()
end catch
fetch next from c into @DBParentId, @Description
end
混合你可能会变得聪明并且混合东西。一种选择可能是使面向Web的插入过程实际插入到轻量级,最小键控/约束表(如队列)中。然后,每分钟左右,让一个代理作业通过记录的调用运行,并批量操作它们。这里没有从根本上改变任何模式,但它使处理异步,因此调用者不必等待,并且通过将请求一起批处理,您可以节省处理能力,捎带SQL最擅长的;基于集合的操作。
另一种选择可能是进行最基于集合的处理(使用检查来防止业务规则或约束违规)。如果有任何失败,您可以为剩余的行分离RBAR流程。如果所有成功,那RBAR流程永远不会被击中。
结论有几种方法可以解决这个问题。我会尝试尽可能多地使用基于集合的操作,除非你有一个非常强大的理由需要逐行粒度。
- 只需正确构造
insert/update
语句,就可以避免大多数错误。 - 如果需要,可以使用带有“空”捕获块的
try/catch
,以便故障不会停止整个处理 - 根据您的具体情况的随机几率和结束,您可能希望或需要混合这两种方法
以上是关于如何使用SQL Server中的DataTable模拟“批量”插入的主要内容,如果未能解决你的问题,请参考以下文章
通过数据库上下文将空 DataTable 传递给 SQL Server 存储过程
将 DataTable 的所有行插入到 SQL Server 表中,包括 Id 值
DataTable 到带有实体框架的 SQL Server 表