插入几行后,Sql server Insert 变慢

Posted

技术标签:

【中文标题】插入几行后,Sql server Insert 变慢【英文标题】:Sql server Insert slows down after inserting few rows 【发布时间】:2018-07-11 23:00:44 【问题描述】:

我正在通过 web api 在 sql server 2008 R2 中插入数据。大约有 300 条记录插入到 3 到 4 个表中。前 20 到 30 条记录很容易在几毫秒内插入,之后插入记录需要几秒钟到几分钟。 sql server 安装在 Windows Server 2012 R2 中。

如果我在插入后删除相同的记录,然后再次调用 api 插入相同的数据,插入只需 2 到 3 秒。

这是api代码

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using ProductsApp.ApplicationLogics;
using System.Web.Http.Cors;
using Newtonsoft.Json;

namespace ProductsApp.Controllers

    [EnableCors(origins: "*", headers: "*", methods: "POST")]
    public class DataPostController : ApiController
    
        [AcceptVerbs("POST")]
        public string DataPost([FromBody] List<Models.ReadingData> model)
        
            if (model == null)
            
                return "Data not found!";
            

            string sql, id1;
            string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["APIConnectionString"].ConnectionString;

            using (SqlConnection con = new SqlConnection(connectionString))
            
                con.Open();

                using (SqlTransaction tran = con.BeginTransaction())
                
                    foreach (var item in model)
                    

                        sql = @"INSERT INTO TableA(Col1, Col2, Col3, Col4) 
                                SELECT @Col1, @Col2, @Col3, @Col4;
                                SELECT SCOPE_IDENTITY();";

                        using (SqlCommand sqlCommand = new SqlCommand(sql, con, tran))
                        
                            sqlCommand.Parameters.AddWithValue("@Col1", item.value1);
                            sqlCommand.Parameters.AddWithValue("@Col2", item.value2);
                            sqlCommand.Parameters.AddWithValue("@Col3", item.value3);

                            try
                            
                                id1 = Convert.ToString(sqlCommand.ExecuteScalar());


                                if (item.amount > 0)
                                                                    
                                    if (item.something != "0")
                                    
                                        sql = @"INSERT INTO TableB(Col1, Col2, Col3)
                                                    SELECT @Col1, @Col2, @Col3;";
                                        using (SqlCommand sqlCommand2 = new SqlCommand(sql, con, tran))
                                        
                                            sqlCommand2.Parameters.AddWithValue("@Col1", id1);
                                            sqlCommand2.Parameters.AddWithValue("@Col2", item.value5);
                                            sqlCommand2.Parameters.AddWithValue("@FiscalYearId", item.value6);

                                            try
                                            
                                                sqlCommand2.ExecuteNonQuery();
                                            
                                            catch (SqlException ex)
                                            
                                                tran.Rollback();
                                                return ex.Message;
                                            
                                                                            
                                    
                                

                                if (item.advanceAmount > 0 || item.outstandingAmount > 0)
                                
                                    sql = @"UPDATE CustomersInfo SET AdvanceAmount=0, OutstandingAmount=0 WHERE CustomerId=@CustomerId;
                                            UPDATE COAR SET IsClear=1 WHERE CustomerId=@CustomerId;
                                            INSERT INTO COAR(FiscalYearId, CustomerId, EntryByUserId, OutstandingAmount, AdvanceAmount) 
                                                SELECT @FiscalYearId, @CustomerId, @EntryByUserId, @OutstandingAmount, @AdvanceAmount;";
                                
                                else
                                
                                    sql = @"UPDATE CustomersInfo SET AdvanceAmount=0 WHERE CustomerId=@CustomerId;
                                                UPDATE COAR SET IsClear=1 WHERE CustomerId=@CustomerId;";
                                

                                using (SqlCommand sqlCommand2 = new SqlCommand(sql, con, tran))
                                
                                    sqlCommand2.Parameters.AddWithValue("@FiscalYearId", item.FiscalYearId);
                                    sqlCommand2.Parameters.AddWithValue("@CustomerId", item.CustomerId);
                                    sqlCommand2.Parameters.AddWithValue("@EntryByUserId", item.MeterReaderId);
                                    sqlCommand2.Parameters.AddWithValue("@OutstandingAmount", item.outstandingAmount);
                                    sqlCommand2.Parameters.AddWithValue("@AdvanceAmount", item.advanceAmount);

                                    try
                                    
                                        sqlCommand2.ExecuteNonQuery();
                                    
                                    catch (SqlException ex)
                                    
                                        tran.Rollback();
                                        return ex.Message;
                                    
                                


                                /*Insert Spot Fine (if any)*/
                                if (item.Fine > 0)
                                
                                    sql = @"INSERT INTO CreditSales(CreditSalesDateAD, CreditSalesDateBS, FiscalYearId, 
                                                CustomerId, ParticularsId, Amount, EntryByUserId, Status, MonthSN, MonthId)  
                                            SELECT @CreditSalesDateAD, @CreditSalesDateBS, @FiscalYearId, 
                                                @CustomerId, @ParticularsId, @Amount, @EntryByUserId, @Status, @MonthSN, @MonthId;";
                                    using (SqlCommand sqlCommand4 = new SqlCommand(sql, con, tran))
                                    
                                        sqlCommand4.Parameters.AddWithValue("CreditSalesDateAD", item.meterReadingDateAD);
                                        sqlCommand4.Parameters.AddWithValue("CreditSalesDateBS", item.meterReadingDateBS);
                                        sqlCommand4.Parameters.AddWithValue("FiscalYearId", item.FiscalYearId);
                                        sqlCommand4.Parameters.AddWithValue("CustomerId", item.CustomerId);
                                        sqlCommand4.Parameters.AddWithValue("ParticularsId", 5); //Always will be 5
                                        sqlCommand4.Parameters.AddWithValue("Amount", item.Fine);
                                        sqlCommand4.Parameters.AddWithValue("EntryByUserId", item.MeterReaderId);
                                        sqlCommand4.Parameters.AddWithValue("Status", "0");
                                        sqlCommand4.Parameters.AddWithValue("MonthSN", item.monthSN);
                                        sqlCommand4.Parameters.AddWithValue("MonthId", item.MonthId);

                                        try
                                        
                                            sqlCommand4.ExecuteNonQuery();
                                        
                                        catch (SqlException ex)
                                        
                                            tran.Rollback();
                                            return ex.Message;
                                        
                                    
                                

                                /*If any tap repair complain*/
                                if (item.TapRepair == 1)
                                
                                    sql = @"INSERT INTO TapRepairs(ComplainDateAD, ComplainDateBS, FiscalYearId, CustomerId, ComplainTypeId,
                                                        RepairDateAD, RepairDateBS, RepairDescription, RepairByUserId)
                                            SELECT @ComplainDateAD, @ComplainDateBS, @FiscalYearId, @CustomerId, @ComplainTypeId,
                                                        @RepairDateAD, @RepairDateBS, @RepairDescription, @RepairByUserId;";

                                    using (SqlCommand sqlCommand5 = new SqlCommand(sql, con, tran))
                                    
                                        sqlCommand5.Parameters.AddWithValue("@ComplainDateAD", item.meterReadingDateAD);
                                        sqlCommand5.Parameters.AddWithValue("@ComplainDateBS", item.meterReadingDateBS);
                                        sqlCommand5.Parameters.AddWithValue("@FiscalYearId", item.FiscalYearId);
                                        sqlCommand5.Parameters.AddWithValue("@CustomerId", item.CustomerId);
                                        sqlCommand5.Parameters.AddWithValue("@ComplainTypeId", item.Remarks);
                                        sqlCommand5.Parameters.AddWithValue("@RepairDateAD", item.meterReadingDateAD);
                                        sqlCommand5.Parameters.AddWithValue("@RepairDateBS", "");
                                        sqlCommand5.Parameters.AddWithValue("@RepairDescription", "");
                                        sqlCommand5.Parameters.AddWithValue("@RepairByUserId", item.MeterReaderId);

                                        try
                                        
                                            sqlCommand5.ExecuteNonQuery();
                                        
                                        catch (SqlException ex)
                                        
                                            tran.Rollback();
                                            return ex.Message;
                                        
                                    
                                

                            
                            catch (SqlException ex)
                            
                                if (ex.Message.Contains("MeterReadingEntries_FYID_MID_CID"))
                                
                                    //If meter reading entry already done
                                    continue;
                                
                                else
                                
                                    tran.Rollback();
                                    return ex.Message;
                                
                            
                        
                    

                    tran.Commit();
                    con.Close();
                    con.Dispose();
                
            

            return "ok";
        
    

每个表最多只能包含 10 列。 可能是什么原因? api有什么问题吗?为什么删除并重新插入同一条记录后插入速度很快?

更新: 探查器图像 Profiler Attached Image

【问题讨论】:

我们不可能在这里提供帮助,因为您已将问题的实际相关部分排除在外。请记住,在进行事务时,事务越大,对性能的影响就越大,因为引擎必须在需要时无法展开它。 这里的人肯定很快就会投反对票。 OP 从未在这里发布过另一个问题,并且在不到 10 分钟的时间内收到了 2 次反对票。我同意这个问题目前很糟糕,但不要把需要帮助的人赶走。让他们有机会解决他们的问题。 @SeanLange 我已经更新了我的代码。谢谢我是新来的,我正在学习 ***。 让我很头疼的最大性能问题是您在循环中执行此操作。这被称为 RBAR(逐行痛苦行)。然后对于每一行,您都在执行大量 DML 语句。我将从 C# 中取出所有这些逻辑,并制作一个存储过程,该过程可以接收您的集合的表值参数。然后你可以根据这个集合编写它,性能会非常快。这也是将数据分离到自己的层的良好开端。 目标表中是否有触发器或数千个索引?这可能是值得一试的东西。此外,如果您安装了 SQL Server 分析器,请打开它,启动跟踪(使用默认值)并检查是否有任何语句在数据库中执行日志时间。 【参考方案1】:

除了创建存储过程并将批处理发送到存储过程之外,我肯定会补充一点,每个循环中每个查询的执行计划可能是不同的。

这篇文章已经解决了这个问题: SQL Query slow in .NET application but instantaneous in SQL Server Management Studio

看看erikkallen写的答案

【讨论】:

以上是关于插入几行后,Sql server Insert 变慢的主要内容,如果未能解决你的问题,请参考以下文章

插入行后从 form2 刷新 form1 gridview

SQL 插入日期时间 变量值

SQL Server INSERT时间戳插入其他内容[重复]

使用 INSERT INTO (SQL Server 2005) 插入多个值

SQL Server 基本INSERT语句

sql server 2012中插入记录INSERT后面+INTO与不+之间有啥区别?