2012-04-25 4 views
24

Qual è il modo più rapido per esportare file (BLOB) memorizzati in una tabella SQL Server in un file sul disco rigido? Ho più di 2,5 TB di file (90 kb avg) memorizzati come varbinary e ho bisogno di estrarne ciascuno su un disco rigido locale il più rapidamente possibile. BCP sembra funzionare, ma ci vorranno più di 45 giorni con la velocità che sto vedendo, e sono preoccupato che il mio script fallirà a un certo punto perché Management Studio esaurirà la memoria.modo più rapido per esportare i BLOB dalla tabella in singoli file

+1

È improbabile che questo sia un problema di prestazioni BCP. Che aspetto hanno i tuoi utilizzi del disco durante questo? – RBarryYoung

+0

La lunghezza media della coda del disco è inferiore a un decimo di secondo e il tempo di risposta medio è inferiore a 5 ms durante il test, il che mi sembra soddisfacente. Ad ogni modo sembra una prestazione ragionevole da parte di BCP, speravo solo che potesse esserci un modo più veloce. – influent

+0

Potrebbe voler leggere la seguente domanda su DBA.SE: [Ottimizzazione delle prestazioni BCP per i dati BLOB] (http://dba.stackexchange.com/questions/5025/optimising-bcp-performance-for-blob-data/). Tratta il caso di bcp e blob. – Marian

risposta

28

Ho provato a utilizzare una funzione CLR ed era più veloce del doppio rispetto a BCP. Ecco il mio codice.

Metodo Originale:

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

CLR Metodo:

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) 

codice C# per la funzione CLR

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; 
     } 
     } 
    } 
} 
+3

Ho raddoppiato le prestazioni utilizzando SET NOCOUNT ON e inviando il testo del risultato a una tabella anziché alla finestra Messaggi in SSMS. – influent

+0

Sarebbe bello se T-SQL avesse semplicemente il comando SELECT del campo INTO DUMPFILE di MySQL. – Patrick

+1

Lo fa. Si chiama BULK INSERT. – Marian

-5

L'utilizzo di una soluzione di programmazione è a senso unico, ma la preoccupazione nella domanda originale che uno script potrebbe fallire se SSMS esaurisce la memoria può essere risolta anche creando un lavoro SQL Agent per l'attività. Questo ovviamente ignora completamente la parte relativa alle prestazioni della domanda.

+1

Si prega di fornire un esempio della soluzione proposta invece di dire come le altre soluzioni non funzioneranno. –

+0

O semplicemente cancella la risposta - recupererà anche la reputazione negativa sostenuta ... –

+0

@PeterB Va tutto bene. Questo mostra chiaramente come la mentalità della mandria domini SE e che nessuno capisca davvero la domanda originale. Stai attento. – ajeh

6

Sono venuto qui cercando di esportare il file BLOB con il minimo sforzo. Le funzioni CLR non sono qualcosa che definirei il minimo sforzo. Here descritto più pigri uno, utilizzando 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 

Avrete potenzialmente necessario consentire di eseguire le stored procedure OA sul server (e poi spegnerlo, quando hai finito):

sp_configure 'show advanced options', 1; 
GO 
RECONFIGURE; 
GO 
sp_configure 'Ole Automation Procedures', 1; 
GO 
RECONFIGURE; 
GO 
+1

Ho appena usato questo metodo per generare 979 jpeg da una colonna varbinary di foto di badge ID in un'unità di rete. Ci sono voluti circa 16 secondi per generare le immagini (12mb in totale) e 5 minuti per scrivere il cursore e modificare leggermente il codice fornito. I metodi dell'altra risposta avrebbero richiesto molto più tempo, ma potrebbero essere più efficienti. Questo approccio è stato perfetto per le mie esigenze. – ubercam