实体框架存储过程调用显着减慢

时间:2015-12-18 01:07:08

标签: entity-framework

我使用Entity Framework获得显着降低的性能的原因是什么?以下代码的两个版本都实现了完全相同的目标。

Excel文档包含1700条正在插入SQL Azure数据库的记录。

使用实体框架执行时间:4:55

foreach (IXLRow row in wb.Worksheet(1).RowsUsed())
{
    dbContext.InsertQuestion(row.Cell("B").Value.ToString().Trim(), row.Cell("A").Value.ToString().Trim(), row.Cell("C").Value.ToString().Trim(), row.Cell("D").Value.ToString().Trim(), null);
}

非实体框架执行时间:1:54

foreach (IXLRow row in wb.Worksheet(1).RowsUsed())
{
    using (SqlCommand cmd = new SqlCommand("InsertQuestion", conn))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add(new SqlParameter("@CategoryName", row.Cell("B").Value.ToString().Trim()));
        cmd.Parameters.Add(new SqlParameter("@TypeName", row.Cell("A").Value.ToString().Trim()));
        cmd.Parameters.Add(new SqlParameter("@Text", row.Cell("C").Value.ToString().Trim()));
        cmd.Parameters.Add(new SqlParameter("@Answer", row.Cell("D").Value.ToString().Trim()));
        cmd.ExecuteNonQuery();
    }
}

1 个答案:

答案 0 :(得分:0)

首先,在数据库上创建一个数据类型(比如数据库有VARCHAR和INT类型,你可以创建自己的TYPE。)

CREATE TYPE SurveyAnswerType AS TABLE
(
    CategoryName VARCHAR(255),
    TypeName VARCHAR(255),
    [Text] VARCHAR(255),
    Answer VARCHAR(255)
)

GO

其次,使用新类型作为存储过程的参数

CREATE PROCEDURE InsertSurveyAnswers
    @Answers SurveyAnswerType READONLY
AS

INSERT INTO Answers
(CategoryName, TypeName, [Text], Answer)
SELECT CategoryName, TypeName, [Text], Answer 
FROM @Answers

GO

第三,通过加载一个看起来像你的新类型的表来从C#代码调用存储过程:

DataTable tAnswers = new DataTable();
tAnswers.Columns.Add("CategoryName", typeof(String));
tAnswers.Columns.Add("TypeName", typeof(String));
tAnswers.Columns.Add("Text", typeof(String));
tAnswers.Columns.Add("Answer", typeof(String));

var rows = wb.Worksheet(1).RowsUsed();
var totalRows = rows.Count();
int index = 0;
int bufferSize;

using (SqlCommand cmd = new SqlCommand("InsertAnswers", conn))
{
   cmd.CommandType = CommandType.StoredProcedure;
   cmd.Parameters.Add(new SqlParameter("@SurveyAnswerType",              
                                        SqlDbType.Structured));

 while(index < totalRows)
 {
    int bufferSize = Math.Min(200, totalRows - index);
    foreach (index = index; index < bufferSize; index++)
    {
       var newRow = tAnswerstAnswers.NewRow();
       newRow[0] = rows[index].Cell("A").Value.ToString().Trim();
       newRow[1] = row[index].Cell("B").Value.ToString().Trim();
       newRow[2] = row[index].Cell("C").Value.ToString().Trim();
       newRow[3] = row[index].Cell("D").Value.ToString().Trim();
       tAnswerstAnswers.AddRow(newRow);
    }        
     cmd.Parameters["@SurveyAnswerType"].Value = tAnswers;  
     cmd.ExecuteNonQuery();
 }
}

注意事项:

  • SqlParameter使用SqlDbType.Structured。

  • 连接仅打开和关闭/销毁一次,而不是一次打开 每一行。

  • 您应该使用缓冲区大小来查看最佳大小。

  • 您必须提出自己的实体框架版本 这个 - 但我怀疑你的每次通话都有开销 将这种模式最小化。