Sql server 使用ErrorFile选项时,同步SQL大容量插入会生成失败

Sql server 使用ErrorFile选项时,同步SQL大容量插入会生成失败,sql-server,operating-system,guid,bulkinsert,Sql Server,Operating System,Guid,Bulkinsert,Windows Server 2008 R2企业版、SQL Server 2008 X64、SP3、开发人员版 我构建并动态执行(通过sp_executesql)批量插入命令。一般形式为: BULK INSERT #HeaderRowCheck from "\\Server\Share\Develop\PKelley\StressTesting\101\DataSet.csv" with ( lastrow = 1 ,rowterminator = '\n' ,tablock

Windows Server 2008 R2企业版、SQL Server 2008 X64、SP3、开发人员版

我构建并动态执行(通过sp_executesql)批量插入命令。一般形式为:

BULK INSERT #HeaderRowCheck
 from "\\Server\Share\Develop\PKelley\StressTesting\101\DataSet.csv"
 with
 (
   lastrow = 1
  ,rowterminator = '\n'
  ,tablock
  ,maxerrors = 0
  ,errorfile = 'C:\SQL_Packages\TempFiles\#HeaderRowCheck_257626FB-A5CD-41B8-B862-FAF8C591C7A9.log'
 )
(errorfile名称基于配置的本地文件夹、加载的表以及为每次大容量插入运行新生成的guid——它是一个封装在自己存储过程中的子例程。)

外部进程(以前是SQL代理,现在是WCF服务)启动DTEXEC,启动SSIS包,该包调用数据库中的存储过程,该数据库循环遍历集合、构建查询并为每个集合运行。一个给定数据库中最多可以同时运行四个加载,SQL实例上的多个数据库可以同时运行此加载—尽管从历史上看,容量一直很低,通常一次只有一个实例运行此加载。我们经常这样做,两年多来,它几乎完美无瑕——安全配置正确,存在必要的文件和文件夹,一切正常。(幸运?我不这么认为。)

我们现在预计会有一些严重的工作负载,所以我们正在做一些压力测试,在其中我启动了8次运行,每个运行有四个进程,其中一组四个进程将对要加载的文件进行分割并逐个处理(即最多执行32次同步批量插入。如我所说,压力测试)。低,当启动时,一个或多个将在执行过程中失败,并显示如下错误消息:

从文件“DataSet.csv”加载头信息时遇到错误#4861:无法大容量加载,因为无法打开文件“C:\SQL\U Packages\TempFiles\#HeaderRowCheck\U D0070742-76A5-4175-A1A7-16494103EF25.log”。操作系统错误代码80(文件存在)。

从一次运行到另一次运行,在整个处理过程中,同一文件、数据集或点不会发生错误

从表面上看,听起来好像两个进程试图访问同一个错误文件,这意味着它们独立地生成相同的guid(!)。我的理解是这几乎是不可能的。另一种理论是,同时发生的事情太多(可能多达32个同时运行的大容量插入命令),SQL和/或操作系统不知何故变得混乱(我是DBA,不是网络管理员)。我可以做一些变通,构建我的try-catch块来检查错误4861,然后最多重试三次,但我宁愿避免这样的麻烦

此后,我加入了一个例程,在使用错误文件之前将其名称(带有guid)记录到一个表中。在多次运行和多次失败之后,我看到(a)失败的文件+guid正在记录到我的表中,并且(b)没有记录重复的guid

有人知道会发生什么吗


Philip

我与Microsoft技术支持部门展开了一个案例,经过多次反复讨论,Pradeep M.M.(SQL Server支持技术负责人)解决了所有问题

一般过程:读取文件夹中的文件列表,然后逐个对这些文件执行一系列大容量插入(首先读取第一行,我们对其进行列解析,然后从第二行+行读取数据)。所有批量插入都使用“ErrorFile”选项,以便在用户的数据格式错误时向用户提供我们可以提供的信息。这个过程已经运行了3年多,但在最近的压力测试条件下(在所有文件格式正确的情况下,单个SQL Server实例最多同时执行8次运行),我们得到了上面列出的错误

我们最初认为,由于“已经打开”的错误,在生成GUID时会出现错误,但这种想法最终被放弃了——如果newid()不能正常工作,更多的人将面临更严重的问题

根据Pradeep,以下是批量插入工作原理的逐步过程:

  • 已提交大容量插入命令,并对其进行语法错误分析
  • 然后编译大容量插入命令以生成执行 同样的计划
  • 在编译阶段,如果在查询中指定 ERRORFILE参数,然后我们将创建ERRORFILE.log和 ErrorFile.Error.Txt到指定的文件夹位置(重要信息 这里需要了解的是,文件大小将为0kb)
  • 文件创建完成后,我们将使用删除这两个文件 windows API调用
  • 一旦执行计划就绪,我们就进入执行阶段 并尝试执行批量插入命令,作为其中的一部分,我们将 在文件夹中重新创建ErrorFile.log和ErrorFile.Error.Txt 指定的位置(根据联机丛书文档中的错误) 文件不应该在这个位置,否则我们将失败 执行
  • 一旦执行完成,如果在 批量插入相应的错误会记录到错误文件中 如果没有错误,将删除这两个文件
  • 在失败的运行期间运行ProcMon(Process Monitor)表明,在步骤3中成功创建并打开了错误文件,但在步骤4中没有关闭,导致步骤5生成了我们看到的错误。(对于成功运行,按照预期创建并关闭了文件。)

    对ProcMon的进一步分析表明,在大容量插入尝试之后,另一个运行CMD.EXE的进程正在对文件发出“关闭句柄”操作。我们使用一个包含xp_cmdshell的例程来检索要处理的文件列表,这可能是CMD.EXE进程的原因。下面是提示:

    …SQL Server内部有一些启动CMD.EXE的业务逻辑,由于CMD.EXE是一个子进程,因此它继承父进程打开的所有句柄(因此,这可能是某种时间问题,在CMD.EXE中,它保留启动时打开的文件的句柄,以及所有拥有句柄的文件的句柄