插入几行后,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 变慢的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server INSERT时间戳插入其他内容[重复]