9

BULK INSERT/bcp 是否可以从命名管道读取fifo样式?

也就是说,不是从真正的文本文件中读取,而是 BULK INSERT/bcp 是否可以从位于另一个进程的写入端的命名管道中读取?

例如:

  1. 创建命名管道
  2. 解压文件到命名管道
  3. 使用 bcp 或 BULK INSERT 从命名管道读取

或者:

  1. 创建 4 个命名管道
  2. 将 1 个文件拆分为 4 个流,将每个流写入单独的命名管道
  3. 使用 bcp 或 BULK INSERT 从 4 个命名管道读取到 4 个表

我找到的最接近的是这个家伙(现在无法访问站点),他设法使用bcp 写入命名管道,具有自己的实用程序和用法,如下所示

start /MIN ZipPipe authors_pipe authors.txt.gz 9
bcp  pubs..authors out  \\.\pipe\authors_pipe -T -n

但他无法让反向工作。

因此,在我开始做傻事之前,我想知道从根本上是否可以带有 BULK INSERT 或 bcp 的命名管道中读取。如果可能的话,人们将如何设置它?NamedPipeServerStream.NETSystem.IO.Pipes命名空间中的其他内容是否足够?

例如,使用 Powershell的示例:

[reflection.Assembly]::LoadWithPartialName("system.core")
$pipe = New-Object system.IO.Pipes.NamedPipeServerStream("Bob")

然后什么?

4

4 回答 4

5

不幸的是,SSIS 平面文件适配器、BULK INSERT 和 BCP 都对文件进行了独占写入锁定(即使它实际上并未写入文件)。这就是为什么这不起作用。

我不确定管道是否可以设置为允许同一管道上的两个独占锁而不会受到严重的黑客攻击。我想你可以绕道或侵入 fltmgr.sys :)

正如其他海报所建议的那样,使用 .NET API 进行批量处理或使用 OLEDB 或 ODBC 接口可能更简单,即使这意味着您必须编写自己的文件解析器。

于 2012-06-14T22:24:00.513 回答
5

我已经成功地让 BULK INSERT(但不是 BCP)与 Windows 7 和 SQL Server 2008R2 上的命名管道一起正常工作。有一些技巧。

首先,我必须在两个不同的线程上创建两个命名管道实例,它们都具有相同的管道名称。SQL Server 将打开第一个实例,从中读取几个字节,然后将其关闭,从而导致 WriteFile 在第一个线程中引发 PipeException。SQL Server 然后会立即重新打开命名管道,并从其中流式传输所有数据。如果我没有第二个线程在后台准备好为数据提供服务,SQL Server 将在我的第一个线程有时间从 PipeException 中恢复之前返回一个错误。

其次,我必须在对 WriteFile 的一次调用中写入所有数据。我从一个循环开始,在该循环中我将多个批次写入管道,但 BULK INSERT 只使用了我编写的第一批。它似乎进行了非阻塞读取,并将任何返回零字节的读取视为文件结尾。

第三,如果使用 XML 格式文件,则必须将其写入常规文件。我没有成功让 SQL Server 从管道中读取格式文件。我不知道它是否可以从管道中读取非 XML 格式的文件。

于 2013-07-08T19:24:42.217 回答
5

我会对@DanMenes 发表评论(感谢您的灵感),但出于参考目的,我将其添加为单独的答案。

我已经在 .NET 中制定了一个解决方案,它打开了一个管道(实际上是 2 个,第一个像 @DanMenes 所说的那样被销毁),准备将数据流式传输到它,然后BULK INSERT使用自动生成的格式文件开始。

前提是我可以做类似的事情

  var inMemoryData = new[] {
    new[] { "val1", "val2" },
    new[] { "val3", "val4" },
  };

  using (var importer = new Importer(SqlConnection, "MyTable", "Col1", "Col2"))
  {
    importer.Import(inMemoryData);
  }

我将总结一下 Importer 的实现:

1.创建管道

var stream = new NamedPipeServerStream(name, PipeDirection.Out, 2, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
stream.BeginWaitForConnection(OnConnection, this);

2.接受连接

public void OnConnection(IAsyncResult asyncResult)
{
  Stream.EndWaitForConnection(asyncResult);

  var buffer = Encoding.UTF8.GetBytes(data);
  Stream.Write(buffer, 0, buffer.Length);
  Stream.Close();
}

3. 开始批量插入

var insertCommand = DbConnection.CreateCommand();
insertCommand.CommandText = "BULK INSERT [MyTable] FROM '\\.\pipe\mypipe' WITH (FORMATFILE='c:\path\to\formatfile')";
insertCommand.ExecuteNonQuery();

有关更多详细信息,请参阅GitHub 项目

注意:我还没有在项目中添加性能测试,但初步测试确实显示了 2x 和 5x 相对于 transactional 的性能提升INSERTs

于 2013-11-18T04:15:46.990 回答
-1

BCP接受吗STDIN?如果是这样,您可能想尝试直接通过管道而不创建命名管道......例如:

gunzip authors.txt.gz | bcp schema.tablename
于 2013-02-12T00:19:50.690 回答