可以从命名管道/ fifo读取Sql Server BULK INSERT吗?

时间:2010-02-04 02:44:14

标签: sql-server named-pipes bulkinsert bcp fifo

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

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

例如:

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

    1. 创建4个命名管道
    2. 将1个文件拆分为4个流,将每个流写入单独的命名管道
    3. 从4个命名管道读取到4个表w / bcp或BULK INSERT
    4. 我发现的最接近的是this fellow(网站现在无法访问),他设法将写入一个名为w / bcp的管道,并使用他自己的实用程序和用法如下:

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

      但他无法逆转工作。

      所以在我开始讨论傻瓜的差事之前,我想知道是否可以从中读取带有BULK INSERT或bcp的命名管道。如果可能的话,如何设置它? .NET NamedPipeServerStream命名空间中的System.IO.Pipes或其他内容是否足够?

      例如,example使用Powershell:

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

      然后......什么?

4 个答案:

答案 0 :(得分:5)

我已成功获得BULK INSERT(但不是BCP),以便在Windows 7和SQL Server 2008R2上使用命名管道正常工作。有一些技巧。

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

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

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

答案 1 :(得分:5)

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

I've worked out a solution in .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。启动BULK INSERT

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

有关详细信息,请参阅the GitHub project

注意:我还没有为项目添加性能测试,但是初步测试确实显示了与事务INSERTs相比在2x和5x之间的性能提升。

答案 2 :(得分:4)

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

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

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

答案 3 :(得分:0)

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

gunzip authors.txt.gz | bcp schema.tablename