如何将大文件写入SQL Server FILESTREAM?

14

我在写入SQL Server的FILESTREAM列时遇到了问题,特别是对于大约1.5-2GB大小的文件可以正常处理,但当文件大小达到6GB或更大时,在传输末尾使用.CopyTo()时会不时地出现间歇性IOException错误,显示"The handle is invalid"。

我考虑过分段写入数据,但是SQL Server在允许追加数据之前会复制该字段的后备文件,这会完全破坏大型文件的性能。

以下是代码:

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

也许可以看一下 http://msdn.microsoft.com/zh-cn/library/bb933972(v=sql.105).aspx - paparazzo
那里有一个通用的例子,它将9个字节写入该字段。 - chase
也许是连接超时了。你尝试过增加连接超时时间吗?顺便问一下,为什么要在 SQL Server 上处理这么大的文件呢?这在现今的 SQL Server 中是否成为常见做法了? - ziya
1
到处都有超时。在SqlCommand上以及在事务上(您指定的1天超时时间不起作用,因为默认的最大超时时间是10分钟。您需要编辑一些配置文件来解决这个问题)。 - usr
你需要使用BufferedStream来处理大文件,它在企业应用中也是可行的。 - Kathir
@Kathir:对于.CopyTo调用,所有这些都只会增加一些开销。 - chase
2个回答

5

尽管文档中提到了WriteTimeout,但在至少4.0版本中,它并不受支持,并且会从底层流中抛出InvalidOperationException异常。 - user875318
很遗憾,还要指出的是,在最近版本的.NET中,已经向FileStream添加了缓冲功能,因此不需要在FileStream上使用BufferedStream。 - dmportella

2

如一些评论所建议的那样,问题可能是事务超时引起的。通过运行SQL Server Profiler并观察您的事务是否被回滚,可以验证这一点。

除非另有规定,machine.config具有默认的最大超时时间为10分钟,无法通过代码覆盖。 要增加最大超时时间,请在machine.config的配置设置中添加以下内容:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接