2012-10-03 43 views
13

Tengo un problema al escribir grandes cantidades de datos a la columna FILESTREAM en SQL Server. Específicamente, los archivos pequeños alrededor de 1.5-2GB se manejan bien, pero cuando el tamaño alcanza los 6GB y más, recibo intermitenteIOException "El identificador no es válido" en .CopyTo() hacia el final de la transferencia.Cómo escribir archivos grandes en SQL Server FILESTREAM?

He pensado en escribir los datos en fragmentos, pero SQL Server copia el archivo de respaldo para el campo antes de permitir agregar datos, lo que destruye completamente el rendimiento de los archivos de gran tamaño.

Aquí está el código:

public long AddFragment (string location , string description = null) 
{ 
    const string sql = 
     @"insert into [Fragment] ([Description],[Data]) " + 
      "values (@description,0x); " + 
     "select [Id], [Data].PathName(), " + 
      "GET_FILESTREAM_TRANSACTION_CONTEXT() " + 
     "from " + 
      "[Fragment] " + 
     "where " + 
      "[Id] = SCOPE_IDENTITY();"; 

    long id; 

    using (var scope = new TransactionScope(
     TransactionScopeOption.Required, 
      new TransactionOptions { 
       Timeout = TimeSpan.FromDays(1) 
      })) 
    { 
     using (var connection = new SqlConnection(m_ConnectionString)) 
     { 
      connection.Open(); 

      byte[] serverTx; 
      string serverLocation; 

      using (var command = new SqlCommand (sql, connection)) 
      { 
       command.Parameters.Add("@description", 
        SqlDbType.NVarChar).Value = description; 

       using (var reader = command.ExecuteReader()) 
       { 
        reader.Read(); 
        id = reader.GetSqlInt64(0).Value; 
        serverLocation = reader.GetSqlString (1).Value; 
        serverTx = reader.GetSqlBinary (2).Value; 
       } 
      } 

      using (var source = new FileStream(location, FileMode.Open, 
       FileAccess.Read, FileShare.Read, 4096, 
       FileOptions.SequentialScan)) 
      using (var target = new SqlFileStream(serverLocation, 
       serverTx, FileAccess.Write)) 
      { 
       source.CopyTo (target); 
      } 
     } 

     scope.Complete(); 
    } 

    return id; 
} 
+0

Tal vez mirar a http://msdn.microsoft.com/en-us/library/bb933972(v=sql.105) .aspx – Paparazzi

+0

Hay un ejemplo genérico allí que escribe _9_ bytes en el campo. – chase

+0

Tal vez un tiempo de espera en la conexión. ¿Intentó aumentar los tiempos de espera de conexión, por ejemplo? Por cierto, me pregunto, ¿por qué estás usando SQL Server para archivos tan grandes? ¿Esto se está convirtiendo en una práctica común en SQL Server actualmente? – ziya

Respuesta

3

Yo sugeriría que utilice BufferedStream clase alrededor de su clase FileStream.

También asegúrese de establecer la propiedad WriteTimeOut en la clase SqlFileStream.

aquí a encontrar un post muy bueno que explica todo acerca SqlFileStream http://www.simple-talk.com/sql/learn-sql-server/an-introduction-to-sql-server-filestream/

+0

A pesar de los documentos, WriteTimeout no es compatible y arrojará una InvalidOperationException del Stream subyacente, al menos en 4.0 – user875318

+0

que es una lástima, solo para señalar que no es necesario usar bufferstream en un FileStream a partir de una versión reciente del. la funcionalidad de almacenamiento en la red se ha agregado a FileStream. – dmportella

2

Según lo sugerido por algunos de los comentarios, el problema es probablemente un tiempo de espera de transacción. Puede verificar esto ejecutando el Analizador de SQL Server y mirando para que se retrotraiga su transacción.

A menos que se especifique lo contrario, machine.config tiene un maxTimeout predeterminado de 10 minutos, que no se puede anular mediante el código. Para aumentar el tiempo de espera máximo, añada lo siguiente a la opción de configuración de su machine.config

<system.transactions> 
    <machineSettings maxTimeout="00:30:00" /> 
</system.transactions> 
Cuestiones relacionadas