将blob从表导出到单个文件的最快方法

inf*_*ent 28 sql blob sql-server-2008-r2

将存储在SQL Server表中的文件(blob)导出到硬盘驱动器上的文件的最快方法是什么?我有超过2.5 TB的文件(90 kb avg)存储为varbinary,我需要尽快将每个文件提取到本地硬盘驱动器.BCP似乎有效,但是我会看到它将花费超过45天的时间,而且我担心我的脚本会在某些时候失败,因为Management Studio会耗尽内存.

inf*_*ent 30

我尝试使用CLR功能,它的速度是BCP的两倍多.这是我的代码.

原始方法:

SET @bcpCommand = 'bcp "SELECT blobcolumn FROM blobtable WHERE ID = ' + CAST(@FileID AS VARCHAR(20)) + '" queryout "' + @FileName + '" -T -c'
EXEC master..xp_cmdshell @bcpCommand
Run Code Online (Sandbox Code Playgroud)

CLR方法:

declare @file varbinary(max) = (select blobcolumn from blobtable WHERE ID = @fileid)
declare @filepath nvarchar(4000) = N'c:\temp\' + @FileName
SELECT Master.dbo.WriteToFile(@file, @filepath, 0)
Run Code Online (Sandbox Code Playgroud)

CLR函数的C#代码

using System;
using System.Data;
using System.Data.SqlTypes;
using System.IO;
using Microsoft.SqlServer.Server;

namespace BlobExport
{
    public class Functions
    {
      [SqlFunction]
      public static SqlString WriteToFile(SqlBytes binary, SqlString path, SqlBoolean append)
      {        
        try
        {
          if (!binary.IsNull && !path.IsNull && !append.IsNull)
          {         
            var dir = Path.GetDirectoryName(path.Value);           
            if (!Directory.Exists(dir))              
              Directory.CreateDirectory(dir);            
              using (var fs = new FileStream(path.Value, append ? FileMode.Append : FileMode.OpenOrCreate))
            {
                byte[] byteArr = binary.Value;
                for (int i = 0; i < byteArr.Length; i++)
                {
                    fs.WriteByte(byteArr[i]);
                };
            }
            return "SUCCESS";
          }
          else
             "NULL INPUT";
        }
        catch (Exception ex)
        {          
          return ex.Message;
        }
      }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 通过使用SET NOCOUNT ON并将结果文本发送到表而不是SSMS中的Messages窗口,我再次将性能提高了一倍. (3认同)
  • 您的原始方法看起来更容易使用,所以我尝试了它,我的.jpeg文件已损坏.将-c开关更改为-n(字符到本机)修复了该问题.在弄清楚之后,我毕竟使用了CLR版本,所以,谢谢! (3认同)
  • 仅供参考:文件"损坏"是因为-n格式在文件前面加上4个十六进制的单词,用于显示数据库中blob的长度.如果你在十六进制编辑器之类的东西中删除那些,那么文件加载正常.现在,如果我能找到自动剥离它们的参数...... (3认同)
  • @Marian:BULK INSERT 将数据文件导入到数据库表或视图中。它无法将数据导出到文件。 (2认同)

And*_*y K 12

我来到这里寻找将blob导出到文件中的努力.CLR功能不是我称之为最少努力的东西.这里描述了lazier,使用OLE Automation:

declare @init int
declare @file varbinary(max) = CONVERT(varbinary(max), N'your blob here')
declare @filepath nvarchar(4000) = N'c:\temp\you file name here.txt'

EXEC sp_OACreate 'ADODB.Stream', @init OUTPUT; -- An instace created
EXEC sp_OASetProperty @init, 'Type', 1; 
EXEC sp_OAMethod @init, 'Open'; -- Calling a method
EXEC sp_OAMethod @init, 'Write', NULL, @file; -- Calling a method
EXEC sp_OAMethod @init, 'SaveToFile', NULL, @filepath, 2; -- Calling a method
EXEC sp_OAMethod @init, 'Close'; -- Calling a method
EXEC sp_OADestroy @init; -- Closed the resources
Run Code Online (Sandbox Code Playgroud)

您可能需要允许在服务器上运行OA存储过程(然后在完成后将其关闭):

sp_configure 'show advanced options', 1;  
GO  
RECONFIGURE;  
GO  
sp_configure 'Ole Automation Procedures', 1;  
GO  
RECONFIGURE;  
GO
Run Code Online (Sandbox Code Playgroud)

  • 我刚刚使用这种方法从ID列徽章照片的varbinary列生成979 jpegs到网络驱动器.生成图像大约需要16秒(总共12mb),写入光标需要5分钟,稍微修改一下提供的代码.另一个答案的方法需要更长的时间,但可能更有效.这种方法非常适合我的需求. (2认同)