代码之家  ›  专栏  ›  技术社区  ›  Peter Radocchia

Sql Server大容量插入能否从命名管道/fifo读取?

  •  7
  • Peter Radocchia  · 技术社区  · 16 年前

    大容量插入/bcp是否可以从命名管道中读取, fifo

    也就是说,是否可以使大容量插入/bcp从另一个进程的写入端的命名管道读取,而不是从真实文本文件读取?

    1. 创建命名管道
    2. 将文件解压缩到命名管道
    3. 使用bcp或大容量插入从命名管道读取

    或:

    1. 创建4个命名管道
    2. 将1个文件拆分为4个流,将每个流写入单独的命名管道

    我找到的最接近的是 this fellow 带有bcp的命名管道,具有自己的实用程序和用法,如下所示:

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

    但他无法让相反的方式发挥作用。

    所以,在我开始做傻事之前,我想知道阅读是否从根本上是可能的 带有批量插入或bcp的命名管道。如果可能的话,我们将如何设置它?将 NamedPipeServerStream System.IO.Pipes 名称空间是否足够?

    example 使用Powershell:

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

    然后……什么?

    4 回复  |  直到 16 年前
        1
  •  5
  •   Dan Menes    13 年前

    我已成功地使大容量插入(但不是BCP)在Windows 7 ans SQL Server 2008R2上正确使用命名管道。这里有一些技巧。

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

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

        2
  •  5
  •   Grimace of Despair    12 年前

    我想对@DanMenes发表评论(感谢您的启发),但出于参考目的,我将添加它作为一个单独的答案。

    I've worked out a solution in .NET BULK INSERT 使用自动生成的格式文件。

      var inMemoryData = new[] {
        new[] { "val1", "val2" },
        new[] { "val3", "val4" },
      };
    
      using (var importer = new Importer(SqlConnection, "MyTable", "Col1", "Col2"))
      {
        importer.Import(inMemoryData);
      }
    

    我将总结导入器的实施情况:

    1.创建管道

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

    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();
    

    the GitHub project

    注意:我还没有将性能测试添加到项目中,但初步测试确实显示,在事务方面,性能提高了2倍到5倍 INSERTs .

        3
  •  4
  •   Thomas Kejser    14 年前

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

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

        4
  •  -1
  •   slm Vikas Hardia    13 年前

    BCP STDIN

    gunzip authors.txt.gz | bcp schema.tablename