插入时截断的长字符串

3
我正在运行一个使用LINQ to SQL与SQL Server 2008 R2标准版通信的.NET 4.0应用程序。我有一张表,其中包含一个nvarchar(max)类型的列,并且该应用程序在其操作中填充该列。
对于大小大于 ~30 MB 的字符串,我们发现一旦插入\更新完成,部分字符串会被截断,服务器存储的不是完整的字符串。问题在于,字符串在可变位置被截断(在截断后仍剩下30 MB以上的数据),因此没有固定点可以指向某个尺寸限制(虽然这仍可能是原因之一)。
在插入时我没有看到任何错误,虽然有时我注意到在这样长时间的插入\更新期间SQL服务器关闭了连接-但在这种情况下不应该回滚操作吗?
希望得到一些想法。不确定如何继续。

你可能需要将其存储为文本而不是nvarchar(max)。根据该行中包含的其他数据,您可能会遇到总行宽的限制。请参阅https://technet.microsoft.com/zh-cn/library/ms186981(v=sql.105).aspx - LordBaconPants
4
@LordBaconPants,text和ntext数据类型已被弃用,不应在新的实现中使用。微软明确表示应该使用varchar(max)和nvarchar(max)。 - Stavros Zotalis
在插入字符串之前,如果它们太长,有什么理由不检查它们的大小呢?然后你可以在插入之前将它们分割。 - Rufus L
感谢 @RufusL。无论如何,目前这不是一个选择,我个人也有绕过我不理解根源的问题的困难。 - user181218
1
你是如何确定字符串被截断的?如果你使用管理工具来进行判断,那么可能会产生误导。 - Jason Boyd
显示剩余4条评论
2个回答

3
我猜测不是SQL Server或者连接插入数据出了问题,我想这可能是在设置命令参数值或应用程序内部出现的数据损坏导致的。我尝试调整连接和命令超时时间,在插入时诱导它们,你对取消的隐式事务会回滚的假设是正确的。这里有一个例子:
// Use connection with timeout of 1 second to generate a timeout when inserting
using (var conn = new SqlConnection(@"Data Source=(localdb)\mssqllocaldb;Integrated Security=SSPI;Initial Catalog=tempdb;Connection Timeout=1"))
using (var cmd = conn.CreateCommand())
{
    cmd.CommandTimeout = 1;
    conn.Open();
    cmd.CommandText = @"if not exists(select * from sys.tables where name = 'LongStringTruncation')
                        begin
                            create table LongStringTruncation (Data nvarchar(max));
                        end";
    cmd.ExecuteNonQuery();

    cmd.CommandText = "insert LongStringTruncation values (@t)";
    var t = cmd.CreateParameter();
    t.DbType = DbType.String;
    t.ParameterName = "@t";
    t.Value = new String('A', 30000000); // 30,000,000 chars = 60MB
    cmd.Parameters.Add(t);
    cmd.ExecuteNonQuery();
}

当查询在超时之前完成时(即成功),以下查询显示传输并插入了全部3000万个字符;当查询由于超时失败时,表格为空。

select len(Data) from LongStringTruncation;

请注意,我在这里使用的是SQL 2014,因此在SQL 2008 R2中可能存在错误,而这个测试可以揭示这个错误。我的测试还使用参数,如果您使用字符串连接来构建SQL,则这可能是另一个问题的来源。
如果以上两种情况都无法说明问题,那么唯一合理的结论就是应用程序在插入数据之前以某种方式截断了数据。考虑到随机性质,我会认为获取字符串数据的方式(例如在读取结果之前没有刷新的缓冲流),或者在获取值/发出完成信号时发生的一些多线程竞争将是我首要怀疑的对象。

0

我曾经遇到过同样的问题。 通过更改存储过程中输入参数的数据类型已解决。

再次检查以下几点: 存储过程的输入参数数据类型应与插入值的表列数据类型相同。

还要在您的C#代码中进行检查。

数据类型及其长度,例如:VARCHAR(50) 在SP、表和代码中应该相同。


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