插入时截断的长字符串

Posted

技术标签:

【中文标题】插入时截断的长字符串【英文标题】:Long strings truncated at insertion time 【发布时间】:2015-07-08 00:07:13 【问题描述】:

我正在运行一个 .NET 4.0 应用程序,该应用程序使用 LINQ to SQL 与 SQL Server 2008 R2 标准版进行通信。我有一个包含nvarchar(max) 类型列的表,并且应用程序使用字符串填充该列作为其操作的一部分。

对于大小 > ~30 MB 的字符串,我们发现一旦插入\更新完成,部分字符串会被截断,并且存储在服务器中的不是完整的字符串。问题是字符串在可变位置被截断(截断后我们仍然留下超过 30 MB 的数据),所以没有一些固定点可以引导我走向一些大小限制的方向(尽管这仍然可能就是这样)。

我没有看到插入时间有任何错误,尽管有时我注意到在如此长的插入\更新期间 SQL 服务器会关闭连接 - 但在这种情况下操作不应该回滚吗?

希望有一些想法。不知道如何进行。

【问题讨论】:

您可能需要将其存储为文本而不是 nvarchar(max)。根据您在该行中拥有的其他数据,您可能会碰到总行宽。看看technet.microsoft.com/en-us/library/… @LordBaconPants text 和 ntext 数据类型已被弃用,不应用于新的实现。 MS 明确指出你应该使用 varchar(max) 和 nvarchar(max) 为什么要将 30mb 的字符串数据存储在单个 db 列中?好像您在数据库中有建模问题。此外,在我看来,您的截断问题可能仍然存在于您的应用程序中。如果您使用的是 Web 服务,则可能存在发送和接收限制,例如在 WCF 服务的情况下:***.com/questions/884235/… 如果字符串太长,有什么理由在插入字符串之前不检查它们的大小?然后你可以在插入之前拆分它们。 你是如何确定字符串被截断的?如果您正在使用 Management Studio 做出决定,则可能会产生误导。 【参考方案1】:

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

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

在你的 C# 代码中也检查相同的内容。

数据类型及其长度 For Ex: VARCHAR(50) 对于 SP、Table 和 code 应该是相同的。

【讨论】:

【参考方案2】:

我怀疑它不是 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();

当这成功时(即查询在超时之前完成);以下查询显示所有 30,000,000 个字符都已传输和插入;当超时失败时,表为空。

select len(Data) from LongStringTruncation;

请注意,我在这里使用了 SQL 2014,因此 SQL 2008 R2 中可能存在一个错误,该测试可以发现该错误。我的测试也使用参数,如果您改为使用字符串连接来构建 SQL,这可能是另一个问题来源。

如果这些都不能解释问题,那么唯一有意义的结论是应用程序本身在插入数据之前以某种方式截断了数据。鉴于随机性,我认为获取字符串数据的方式(例如,在读取结果之前没有刷新的缓冲流),或者在获取值/信号完成时的一些多线程竞争将是我的第一个嫌疑人。

【讨论】:

以上是关于插入时截断的长字符串的主要内容,如果未能解决你的问题,请参考以下文章

尽管数据看似合适,但插入时“字符串或二进制数据将被截断”

在枚举字段(DB)中插入字符串值(java)时获取“列的数据被截断”

把表A 数据插入表B时提示 ‘将截断字符串或二进制数据。 语句已终止’ 。如何找到被截断数据或字段。

从 .net 类型的数据集插入时,备注字段值被截断为大约 1000 个字符

sqlserver插入语句报“将截断字符串或二进制数据”怎么解决,怎么回事?

MySQL 在特殊字符处截断字符串