chamara
chamara

Reputation: 12711

Optimize Long running update query

I have written following method with three sql queries in order to update a single column in a single table.since there are nearly 10000 records to be updated it takes more than 20 mins to complete.is there any other better way to do this updation.some thin like set based update...

private void UpdateLatest()
    {
        string connstr = "Data Source=CHAMARA-PC;Initial Catalog=PHPA_Production_fromEWP;Integrated Security=True";
        using (SqlConnection conn = new SqlConnection(connstr))
        {
            conn.Open();
            SqlTransaction myTransaction = conn.BeginTransaction();
            try
            {
                DataTable dt = new DataTable();
                DataTable DTT = new DataTable();

                string command = "select dh.DocumentNumber,max(dr.RevisionDate) as latestdate from " +
                  "tblDocumentHeader dh inner join tblDocumentRevision dr on dh.DocumentHeaderID=dr.DocumentHeaderID " +
                      "group by dh.DocumentNumber ";


                using (SqlCommand cmd = new SqlCommand(command, conn, myTransaction))
                {
                    using (SqlDataAdapter adapt = new SqlDataAdapter())
                    {
                        adapt.SelectCommand = cmd;
                        adapt.Fill(dt);

                    }
                }
                label1.Text = dt.Rows.Count.ToString();
                foreach (DataRow item in dt.Rows)
                {
                    try
                    {
                        int res = 0;
                        string query2 = "select dr.DocumentRevisionID from " +
                  "tblDocumentHeader dh inner join tblDocumentRevision dr on dh.DocumentHeaderID=dr.DocumentHeaderID " +
                  " where dh.DocumentNumber='" + item["DocumentNumber"].ToString().Trim() + "' and dr.RevisionDate='" + item["latestdate"].ToString().Trim() + "'";

                        using (SqlCommand cmd = new SqlCommand(query2, conn, myTransaction))
                        {
                            using (SqlDataAdapter adapt = new SqlDataAdapter())
                            {
                                adapt.SelectCommand = cmd;
                                adapt.Fill(DTT);

                            }
                        }

                        foreach (DataRow Ritem in DTT.Rows)
                        {
                            string updatequery = "update tblDocumentRevision set LatestRev='latest' where DocumentRevisionID='" + Ritem["DocumentRevisionID"].ToString().Trim() + "'";

                            using (SqlCommand cmd = new SqlCommand(updatequery, conn, myTransaction))
                            {
                                cmd.ExecuteNonQuery();

                                res++;

                            }
                        }
                        listBox1.Items.Add(item["DocumentNumber"].ToString() + " " + "updated");

                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                }
                myTransaction.Commit();
                MessageBox.Show("successfully updated");
            }
            catch (Exception ex)
            {
                myTransaction.Rollback();
                MessageBox.Show(ex.Message);

            }
        }
    }

Upvotes: 0

Views: 206

Answers (2)

marc_s
marc_s

Reputation: 754298

I don't have your database at hand to test this, but basically, your code boils down to this:

DECLARE @Temp TABLE (DocNumber INT, LatestDate DATETIME)

INSERT INTO @Temp(DocNumber, LatestDate)
    SELECT 
        dh.DocumentNumber, MAX(dr.RevisionDate) 
    FROM 
        dbo.tblDocumentHeader dh 
    INNER JOIN 
        dbo.tblDocumentRevision dr ON dh.DocumentHeaderID = dr.DocumentHeaderID
    GROUP BY 
        dh.DocumentNumber

UPDATE 
    dbo.tblDocumentRevision 
SET 
    LatestRev = 'latest' 
FROM
    dbo.tblDocumentRevision dr
INNER JOIN
    dbo.tblDocumentHeader dh ON dh.DocumentHeaderID = dr.DocumentHeaderID 
INNER JOIN
    @Temp t ON dh.DocumentNumber = t.DocNumber AND dr.RevisionDate = t.LatestDate

This can be very easily wrapped in a stored procedure, it does not use any dead slow cursors, and it does not cause any SQL injection possibilities.

Upvotes: 3

TomTom
TomTom

Reputation: 62093

since there are nearly 10000 records to be updated it takes more than 20 mins to complete

Learn SQL.

Ok, first - 10.000 update statements = 20 minutes means your server is a laptop with a slow disc, not a database server. This is WAY too long. The way you do is horrific slow, but at the end... 20 minutes is way too slow. If this is a real database - get a server for it. You do less than 10 updates per second, even a normal desktop can handle about 75.

Now:

You do select then update. Why? Why not do

update tblDocumentRevision set LatestRev='latest' where DocumentRevisionID IN (x,y,z)

and fire one off for every 100 or so documents? That brutally cuts down on the number of statements you issue.

On top if that is too sow you should fire them off async - prepare statement 2 while statement 1 executes, or even fire them off a number of worker threads in parallel.

And finally, SQL basics: is there an index on DocumentRevisionID? And third there is no need to use an adapter and a dta table here. This is sloq, clunky and in general avoids proper programming practices.

Upvotes: 2

Related Questions