-1

I am inserting data in sql server 2008 R2 from web api. There are about 300 records that are inserted in 3 to 4 tables. First 20 to 30 records are easily inserted in few millisecond after that it will take few seconds to few minutes to insert records. The sql server is installed in Windows Server 2012 R2.

If I delete the same record after it is inserted and then again call the api to insert same data, it will just take 2 to 3 seconds to insert.

This is the api code

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";
        }
    }
}

Each table contains max 10 columns only. What may be the cause? Is there anything wrong in the api? Why the insert is fast after the same record is deleted and re-inserted?

Update: Profiler Image Profiler Attached Image

  • 3
    We can't possibly help here because you took the actual relevant part of your question out. Keep in mind when doing transactions the larger the transaction, the greater the impact on performance because the engine has to be unable unwind it if it needs to. – Sean Lange Feb 01 '18 at 15:05
  • 3
    People here sure are quick to downvote. The OP has never posted another question here and this received 2 downvotes in less than 10 minutes. I agree the question is pretty poor currently but don't chase people away that need help. Give them a chance to fix their question. – Sean Lange Feb 01 '18 at 15:16
  • @SeanLange I have updated my code. And thanks I am new here and I am learning about StackOverflow. – Kushal Kathayat Feb 01 '18 at 15:19
  • 3
    The big performance issue that is glaring at me is that you are doing this in a loop. This is known as RBAR (row by agonizing row). Then for each row you are doing numerous DML statements. I would take all of this logic out of C# and make a stored procedure that can receive a table valued parameter for your collection. Then you can write this set based and the performance would be screaming fast. It would also be a good start on separating data into its own layer. – Sean Lange Feb 01 '18 at 15:24
  • @SeanLange But when i manually delete the records that is recently inserted and again call the api with same data, it is only taking 3 sec. – Kushal Kathayat Feb 01 '18 at 15:30
  • 1
    Any chance you have triggers or thousands of indexes in the target tables? It might be something worth a check. Also, if you have SQL Server profiler installed, open it, start a trace (go with the defaults) and check if any statement is taking a log time to execute in the database. – kirchner Feb 01 '18 at 16:08
  • @kirchner Only primary key are indexed and I have not used any triggers in the database. I saw the sql server profiler, the same batch of query works quickly for first 20 records then same query will takes few seconds to several minutes to insert other records. But when I delete the same records from the database and re insert the same data, it will insert in 2-3 seconds. I am surprised and confused here. – Kushal Kathayat Feb 01 '18 at 16:13
  • Can you update your post and show some profiler data? Specifically, Reads, Writes, CPU and Duration for some queries that are taking a long time to execute. – kirchner Feb 01 '18 at 16:16
  • Aside from the performance differences when "re-inserting" I would be concerned if an insert process took 3 seconds. That is WAY slower than I would even consider being in the acceptable range. Fixing the process so it is fast this should be nearly instant, not 3 seconds. – Sean Lange Feb 01 '18 at 17:29
  • Before calling the api, I manually restart the sql server from ssms. By doing so it is inserting data quickly. It has solved the problem but I don't know what was causing the problem. – Kushal Kathayat Feb 03 '18 at 10:20
  • @kirchner I have updated the post with profiler data. – Kushal Kathayat Feb 08 '18 at 14:11
  • Did you see the `SELECT IsEligibleForA...` that is taking 30s to complete? I don't see that SELECT in the code you posted but it is a good thing to try and chase down. Pretty much everything else in the trace completes very fast. – kirchner Feb 09 '18 at 15:29
  • @kirchner Yes the problem was in that query, I fix that query now it is working perfectly. Thank you. – Kushal Kathayat Feb 12 '18 at 08:10

1 Answers1

0

In addition to creating stored procedures and sending a batch onto the stored procedure, I would definitely add that probably the execution plan for each query in each loop is different.

This has already been addressed on this post: SQL Query slow in .NET application but instantaneous in SQL Server Management Studio

Look at the answer written by erikkallen