由于nvarchar(max)字段,导致插入语句超时

时间:2018-07-19 15:35:53

标签: entity-framework azure azure-sql-database

我在Azure上有一个Sql Server数据库,用于处理传入的EDI文档。基本上,它接收数据,并将其保存到表的一行中。 “ edi_data”列的大小可以高达7 Meg。

我们已经使用了两年左右,没有任何问题。但是,在过去的两天内,insert语句已超过​​30秒超时,因此引发错误。

此数据库的DTU已从15增加到100。提高DTU确实有助于处理更多的传输,但是今天再次发生此错误。增加之后,最大DTU不会超过35%。

这是由EntityFramework 6生成的插入内容:

 (@0 int,@1 int,@2 datetime2(7),@3 nvarchar(max),@4 nvarchar(max),@5 
 nvarchar(max),@6 nvarchar(max),@7 nvarchar(max),@8 nvarchar(max),@9 
 nvarchar(max),@10 nvarchar(max),@11 nvarchar(max),@12 nvarchar(max),@13 
 nvarchar(max),@14 nvarchar(max),@15 nvarchar(max),@16 nvarchar(max),@17 
 bit,@18 int)INSERT [dbo].[transmission]([transmission_status_id], 
 [transmission_attempts], [transmission_date], [edi_data], [originator_num], 
 [recipient_num], [error_message], [encryption_type], [gisb_version], 
 [receipt_signing_protocol], [receipt_type], [http_request], 
 [request_headers], [http_response], [response_headers], [edi_type], 
 [original_file_name], [file_name], [archive_flag], [group_control_code], 
 [orig_transmission_id], [direction])
 VALUES (@0, @1, @2, @3, @4, @5, @6, @7, @8, @9, @10, @11, @12, NULL, @13, @14, @15, @16, @17, NULL, NULL, @18)

除了增加DTU以外,还有其他解决方法吗? (我知道我可以将“命令超时”增加到30秒以上,但如果可能的话,我想解决速度问题。)

1 个答案:

答案 0 :(得分:2)

nvarchar(max)varbinary(max)类型用于存储CLOB和BLOB。尽管可以直接保存相对较小的缓冲区或字符串,但使用流API将大量数据复制到服务器要高效得多。 这也可以为客户端节省大量内存,因为它不必一次分配整个7MB字符串,这不可避免地会带来垃圾回收损失。

实体框架不直接提供任何流功能。 ADO.NET,特别是SqlClient提供程序。文档中的SqlClient Streaming Support文章介绍了如何使用流技术将大文件加载或存储到BLOB字段中。

文本类型为NVarChar的SqlParameter可以接受TextReader作为值而不是字符串。 SqlClient将从读取器读取数据并将其发送到数据库。

针对此表,存储doc示例:

CREATE TABLE [TextStreams] (  
    [id] INT PRIMARY KEY IDENTITY(1, 1),  
    [textdata] NVARCHAR(MAX)
) 

以下方法会将数据从源流复制到服务器:

  private static async Task StreamTextToServer() {  
     using (SqlConnection conn = new SqlConnection(connectionString)) {  
        await conn.OpenAsync();  
        using (SqlCommand cmd = new SqlCommand("INSERT INTO [TextStreams] (textdata) VALUES (@textdata)", conn)) {  
           using (StreamReader file = File.OpenText("textdata.txt")) {  

              // Add a parameter which uses the StreamReader we just opened  
              // Size is set to -1 to indicate "MAX"  
              cmd.Parameters.Add("@textdata", SqlDbType.NVarChar, -1).Value = file;  

              // Send the data to the server asynchronously  
              await cmd.ExecuteNonQueryAsync();  
           }  
        }  
     }  
  }