Showing posts with label update. Show all posts
Showing posts with label update. Show all posts

Thursday, March 29, 2012

Deafult NULL not working

I am using SQL Server 2000. I have a Column with DataType int and default value specified as (null). But, With Insert or Update if the column value is Blank, 0 is getting inserted instead of the desired NULL.

Thanks

Is there, by chance, a trigger on this table?|||

NO. There is no trigger on this Table.

|||Well... create a complete DDL script for this table and post it here - something must be there.

Also, how you make a insert / update - directly or via some kind of stored proc? There may be a preprocessing in there that you miss, for example.|||

What exactly do you mean by "column value is blank". If you are explicitly trying to force a blank into the field then yes, it is going to get assigned as zero:

create table dbo.testo
( rid int,
x int default (null)
)

insert into dbo.testo select 1, ' '

insert into dbo.testo (rid) select 1

select * from dbo.testo

/*
rid x
-- --
1 0
1 NULL
*/

If, however, you are wanting to insert a row and allow the default to occur you must do something similar to what I hilighted in red

If you want to UPDATE to the default value, you can use syntax something like this:


update dbo.testO
set x=default
where rid =1

|||

YES. The Column Value is getting evaluated to '' as the user did not enter anything for the field on the form. Is there any way '' can be evaluated to NULL instead of 0.

- vmrao

|||declare @.p1 varchar(255)

set @.p1 = ''

insert into Mytable (rid, myintcol)
select 10, nullif(@.p1, '')
|||Thanks. NULLIF worked.

Deadlocks....What is going on?

We have background processes that constantly insert into and update
table A. When we do selects from table A from our end user
application (we have many selects that hit this table), we quite
frequently get deadlocks. Is it not safe to select from a table that
is being updated? Surely we do not have to put (updlock) hint on
all of our queries... Is thier not some way to control this from the
update/insert routines (as opposed to chaning all of our selects)
TIAA few tips that may help:
On your INSERT and UPDATE routines do the following:
1. Make the transactions as fast as possible. For example, do your data
scrubbing and cleaning and error checking first, then issue the transaction
portion.
2. Use the tables and views in the same order (if possible) within those
routines. This will make other parts of your application wait to acquire
locks and should lessen the deadlocks.
3. If you know that your update is going to affect a significant portion of
the table, you may wish to consider a table lock hint in the query itself.
This would keep your SELECTs from even beginning to view the table while it
was under a large and lengthy update.
If you don't mind your SELECTS looking at data that is under modification,
you may wish to set your ANSI Transaction Isolation Level to READ
UNCOMMITTED. This will allow for dirty reads and so forth. You wouldn't
have to modify all of your SELECT queries, just SET your session for READ
UNCOMMITTED.
HTH
Rick Sawtell
MCT, MCSD, MCDBA
"Tommy" <talfano@.ncpsolutions.com> wrote in message
news:86ecf3f7.0410051431.54114c50@.posting.google.com...
> We have background processes that constantly insert into and update
> table A. When we do selects from table A from our end user
> application (we have many selects that hit this table), we quite
> frequently get deadlocks. Is it not safe to select from a table that
> is being updated? Surely we do not have to put (updlock) hint on
> all of our queries... Is thier not some way to control this from the
> update/insert routines (as opposed to chaning all of our selects)
> TIA|||your update uses not the same index on the table as the
select does. so you access data in different directions
which could cause a deadlock.
two choices:
- either put a NOLOCk hint on the select
- use the same index for the where-clause on the select &
update
>--Original Message--
>A few tips that may help:
>On your INSERT and UPDATE routines do the following:
>1. Make the transactions as fast as possible. For
example, do your data
>scrubbing and cleaning and error checking first, then
issue the transaction
>portion.
>2. Use the tables and views in the same order (if
possible) within those
>routines. This will make other parts of your application
wait to acquire
>locks and should lessen the deadlocks.
>3. If you know that your update is going to affect a
significant portion of
>the table, you may wish to consider a table lock hint in
the query itself.
>This would keep your SELECTs from even beginning to view
the table while it
>was under a large and lengthy update.
>If you don't mind your SELECTS looking at data that is
under modification,
>you may wish to set your ANSI Transaction Isolation Level
to READ
>UNCOMMITTED. This will allow for dirty reads and so
forth. You wouldn't
>have to modify all of your SELECT queries, just SET your
session for READ
>UNCOMMITTED.
>
>HTH
>Rick Sawtell
>MCT, MCSD, MCDBA
>
>
>"Tommy" <talfano@.ncpsolutions.com> wrote in message
>news:86ecf3f7.0410051431.54114c50@.posting.google.com...
>> We have background processes that constantly insert
into and update
>> table A. When we do selects from table A from our end
user
>> application (we have many selects that hit this table),
we quite
>> frequently get deadlocks. Is it not safe to select
from a table that
>> is being updated? Surely we do not have to put
(updlock) hint on
>> all of our queries... Is thier not some way to control
this from the
>> update/insert routines (as opposed to chaning all of
our selects)
>> TIA
>
>.
>|||Rick,
Thanks for your suggestions. We are trying these out right now. I
don't think locking the entire table is an option, but can try dirty
reads, as the transactions should not take that long to complete.
Thanks again,
Tommy
"Rick Sawtell" <r_sawtell@.hotmail.com> wrote in message news:<#lVO4KzqEHA.3840@.TK2MSFTNGP10.phx.gbl>...
> A few tips that may help:
> On your INSERT and UPDATE routines do the following:
> 1. Make the transactions as fast as possible. For example, do your data
> scrubbing and cleaning and error checking first, then issue the transaction
> portion.
> 2. Use the tables and views in the same order (if possible) within those
> routines. This will make other parts of your application wait to acquire
> locks and should lessen the deadlocks.
> 3. If you know that your update is going to affect a significant portion of
> the table, you may wish to consider a table lock hint in the query itself.
> This would keep your SELECTs from even beginning to view the table while it
> was under a large and lengthy update.
> If you don't mind your SELECTS looking at data that is under modification,
> you may wish to set your ANSI Transaction Isolation Level to READ
> UNCOMMITTED. This will allow for dirty reads and so forth. You wouldn't
> have to modify all of your SELECT queries, just SET your session for READ
> UNCOMMITTED.
>
> HTH
> Rick Sawtell
> MCT, MCSD, MCDBA
>
>
> "Tommy" <talfano@.ncpsolutions.com> wrote in message
> news:86ecf3f7.0410051431.54114c50@.posting.google.com...
> > We have background processes that constantly insert into and update
> > table A. When we do selects from table A from our end user
> > application (we have many selects that hit this table), we quite
> > frequently get deadlocks. Is it not safe to select from a table that
> > is being updated? Surely we do not have to put (updlock) hint on
> > all of our queries... Is thier not some way to control this from the
> > update/insert routines (as opposed to chaning all of our selects)
> >
> > TIA

Deadlocks workaround?

Hi All,

I have read about deadlocks here on Google and I was surprised to read
that an update and a select on the same table could get into a
deadlock because of the table's index. The update and the select
access the index in opposite orders, thereby causing the deadlock.
This sounds to me as a bug in SQL Server!

My question is: Could you avoid this by reading the table with a
'select * from X(updlock)' before updating it? I mean: Would this
result in the update transaction setting a lock on the index rows
before accessing the data rows?

Merry Christmas!
/Fredrik Mllerlouis nguyen (louisducnguyen@.hotmail.com) writes:
> In the example you posted, I typically use a "set transaction" option.
> My understanding is that this would prevent all shared locks. What
> is your opinion (pros/cons) of this? Thanks, Louis.
> SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
> BEGIN TRANSACTION
> SELECT @.id = coalesce(MAX(id), 0) + 1 FROM tbl
> INSERT tbl (id, ...) VALUES (@.id, ...)
> COMMIT TRANSACTION

This is very likely to cause deadlocks. The isolation level does not
affect the ability to get shared locks. It only affects what you can
see if you issue the same statement later in the query.

Try this:

CREATE TABLE tbl (id int NOT NULL)
go
DECLARE @.id int
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
SELECT @.id = coalesce(MAX(id), 0) + 1 FROM tbl
WAITFOR DELAY '00:00:10'
INSERT tbl (id) VALUES (@.id)
COMMIT TRANSACTION

First create the table, then run the batch from two windows. You will
get a deadlock. Add "WITH (UPDLOCK)" after the table, and both
batches will succeed.

--
Erland Sommarskog, SQL Server MVP, sommar@.algonet.se

Books Online for SQL Server SP3 at
http://www.microsoft.com/sql/techin.../2000/books.asp|||Hi Erland,

Wow. I learned my lesson. Thanks, Louis.|||Hi Erland and Louis,
The example you provided was very enlightening in showing the
difference between UPDLOCK and HOLDLOCK/SERIALIZABLE. Thank you!
As to the locking of index and data rows I might come back later with
an example illustrating the problem.
Regards
Fredriksql

deadlocks in sql server

Hi
I'm having a problem with deadlocks in a table in SQL server when
trying to update it through Biztalk 2004. There is no problem when I
use the same Biztalk solution to update a similar dummy table, but
when I try updating the original table in the production database,
some transactions are updated successfully whereas others become the
victim of the deadlock (Transaction (Process ID 185) was deadlocked on
lock resources with another process and has been chosen as the
deadlock victim. Rerun the transaction). The table that is updated is
also being used by another application that just selects rows from it.

As a workaround, I have used recursion in the code that updates the
table. The function is put through a recursive loop whenever the
deadlock exception(#1205) is caught. It keeps on trying to update the
table until the updation is successful or another exception (not the
deadlock one) is caught. i.e.

Bool Update_IVR(string amount, string customer_id)
{
Try
{
//updation code
}
}
Catch (exception ex)
{
If( ex.message == deadlock message)
{
Bool succ =Update_IVR (amount, customer_id) //recursion
Return succ;
}
Else //error handling code
}

After introducing this code, the problem did not occur for the next
13000 transactions. Then I got the error again four times along with a
timeout error (Timeout expired. The timeout period elapsed prior to
completion of the operation or the server is not responding). However
for the next 17000 transactions (to date) this error has not showed
up.

Thanks

HasanHasan (hasan@.mobilink.net) writes:
> I'm having a problem with deadlocks in a table in SQL server when
> trying to update it through Biztalk 2004. There is no problem when I
> use the same Biztalk solution to update a similar dummy table, but
> when I try updating the original table in the production database,
> some transactions are updated successfully whereas others become the
> victim of the deadlock (Transaction (Process ID 185) was deadlocked on
> lock resources with another process and has been chosen as the
> deadlock victim. Rerun the transaction). The table that is updated is
> also being used by another application that just selects rows from it.
> As a workaround, I have used recursion in the code that updates the
> table. The function is put through a recursive loop whenever the
> deadlock exception(#1205) is caught. It keeps on trying to update the
> table until the updation is successful or another exception (not the
> deadlock one) is caught. i.e.
>...
> After introducing this code, the problem did not occur for the next
> 13000 transactions. Then I got the error again four times along with a
> timeout error (Timeout expired. The timeout period elapsed prior to
> completion of the operation or the server is not responding). However
> for the next 17000 transactions (to date) this error has not showed
> up.

It seems that you have locking problems in your application, and you
need to perform further analysis to find out where the problem might lie.

Deadlock happens when two processes is trying to access resources already
locked by the other. Here is a simple example:

BEGIN TRANSACTION BEGIN TRANSACTION
UPDATE tbla UPDATE tblb
SET col = 12 SET col = 98
WHERE keycol = 1 WHERE keycol = 8

UPDATE tblb UPDATE tbla
SET col = 88 SET col = 546
WHERE keycol = 8 WHERE keycol = 1
COMMIT TRANSACTION COMMIT TRANSACTION

This will deadlock, when the two processes come to their second UPDATE
statement, they will wait for each other. SQL Server detects this
situation and select one as a deadlock victim.

"Timeout expired" on the other hand can have many causes. This is a timeout
which is set up by the client library, and of which SQL Server has no
knowledge. A timeout could elapse because of long processing time, but
also because the process is blocked by another process. Important to
know is that when you get an timeout expired, you should probably submit
a "IF @.@.trancount > 0 ROLLBACK TRANSACTION", because there is no automatic
rollback in this case.

I would assume that in your case the Timeout Expired was due to blocking.

In order to understand the cause of deadlocks, you need to get more
information. One way is to set up a Profiler trace to catch deadlocks.
You can also enable trace flags 1204 and 3605 by adding -T1204 and -T3605
to the startup parameters in Enterprise Manger, and restart SQL Server.
In this case, each deadlock will be logged in the SQL Server error log.
In fairly cryptic manner, but neverless.

To detect blocking and what the involved processes are doing, I have a
stored procedure, which is good for this. It's called aba_lockinfo and
you find it on http://www.sommarskog.se/sqlutil/aba_lockinfo.html.

--
Erland Sommarskog, SQL Server MVP, sommar@.algonet.se

Books Online for SQL Server SP3 at
http://www.microsoft.com/sql/techin.../2000/books.asp|||
Thanks for your reply. I have a better understadning of whats going on
now. Can you please explain to me how to set the trace flags you've
mentioned.

Thanks
Hasan

*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!|||Hasan Sheikh (hasan@.mobilink.net) writes:
> Thanks for your reply. I have a better understadning of whats going on
> now. Can you please explain to me how to set the trace flags you've
> mentioned.

As I said:

You can also enable trace flags 1204 and 3605 by adding -T1204 and -T3605
to the startup parameters in Enterprise Manger, and restart SQL Server

To get there, right-click the server in EM, select Properties. Startup
Parameters is a button at the buttom of the General tab.

--
Erland Sommarskog, SQL Server MVP, sommar@.algonet.se

Books Online for SQL Server SP3 at
http://www.microsoft.com/sql/techin.../2000/books.aspsql

Tuesday, March 27, 2012

Deadlocks & Transaction Isolation Level

If I understand correctly, when using a Read Committed isolation level, the
most common reason for a deadlock is because two processes update a set of
tables in different order. However, it seems that when using a Repeatable
Read isolation level, the odds of a deadlock increase significantly.
For example, open Management Studio and create two different connections
against the AdventureWorks database. In both connections execute the
following:
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Begin Tran
SELECT EmployeeID From HumanResources.Employee Where EmployeeID = 1
Then, in the first connection execute the following (but do not commit the
transaction):
Update HumanResources.Employee Set MaritalStatus = 'M' Where EmployeeID = 1
In the second connection execute the exact same line. This will cause a
deadlock error in the second connection. We get a deadlock even though both
processes are performing the exact same action in the exact same order.
This example may not be the best but is my assumption correct that when
using Repeatable Read, the likelihood of a deadlock error is greater than
when using Read Committed?
Thanks, Amos.
> when using a Read Committed isolation level, the
> most common reason for a deadlock is because two processes
> update a set of tables in different order.
not exactly. 2 processses may update rows in only one table and still
clinch in a deadlock.
|||Hi Amos
Yes, your understanding is correct. Using a higher isolation level like
repeatable read has tradeoffs.
In read committed the locks on the SELECT would be released as soon as the
SELECT was finished. In repeatable read, the SELECT (shared) locks are not
released. The good news is that each transaction is guaranteed to read the
same data throughout the transaction. The bad news is there is a greater
chance of deadlock. Each connection has a shared lock on the row in the
Employee table, and wants an exclusive lock. Neither can get the exclusive
lock because the other has the shared lock, so you have deadlock.
One of the first suggestions we give to try to reduce deadlock is to reduce
your isolation level; in this case, bring it back to read committed.
Another solution here would be to use an UPDLOCK hint when you do the
select. Then the first process would get an update lock, not a shared lock,
and when the second process tried to get the update lock, it would be
blocked. The first process could then get the exclusive lock and do the
update operation, and finish the transaction. Then the second process could
get first the update lock, then the exclusive lock, and then finish, with no
deadlock occurring.
HTH
Kalen Delaney, SQL Server MVP
www.solidqualitylearning.com
"Amos Soma" <amos_j_soma@.yahoo.com> wrote in message
news:%23$22cVEKGHA.3960@.TK2MSFTNGP09.phx.gbl...
> If I understand correctly, when using a Read Committed isolation level,
> the most common reason for a deadlock is because two processes update a
> set of tables in different order. However, it seems that when using a
> Repeatable Read isolation level, the odds of a deadlock increase
> significantly.
> For example, open Management Studio and create two different connections
> against the AdventureWorks database. In both connections execute the
> following:
> SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
> Begin Tran
> SELECT EmployeeID From HumanResources.Employee Where EmployeeID = 1
>
> Then, in the first connection execute the following (but do not commit the
> transaction):
> Update HumanResources.Employee Set MaritalStatus = 'M' Where EmployeeID =
> 1
> In the second connection execute the exact same line. This will cause a
> deadlock error in the second connection. We get a deadlock even though
> both processes are performing the exact same action in the exact same
> order.
> This example may not be the best but is my assumption correct that when
> using Repeatable Read, the likelihood of a deadlock error is greater than
> when using Read Committed?
> Thanks, Amos.
>
>

Deadlocks & Transaction Isolation Level

If I understand correctly, when using a Read Committed isolation level, the
most common reason for a deadlock is because two processes update a set of
tables in different order. However, it seems that when using a Repeatable
Read isolation level, the odds of a deadlock increase significantly.
For example, open Management Studio and create two different connections
against the AdventureWorks database. In both connections execute the
following:
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Begin Tran
SELECT EmployeeID From HumanResources.Employee Where EmployeeID = 1
Then, in the first connection execute the following (but do not commit the
transaction):
Update HumanResources.Employee Set MaritalStatus = 'M' Where EmployeeID = 1
In the second connection execute the exact same line. This will cause a
deadlock error in the second connection. We get a deadlock even though both
processes are performing the exact same action in the exact same order.
This example may not be the best but is my assumption correct that when
using Repeatable Read, the likelihood of a deadlock error is greater than
when using Read Committed?
Thanks, Amos.> when using a Read Committed isolation level, the
> most common reason for a deadlock is because two processes
> update a set of tables in different order.
not exactly. 2 processses may update rows in only one table and still
clinch in a deadlock.|||Hi Amos
Yes, your understanding is correct. Using a higher isolation level like
repeatable read has tradeoffs.
In read committed the locks on the SELECT would be released as soon as the
SELECT was finished. In repeatable read, the SELECT (shared) locks are not
released. The good news is that each transaction is guaranteed to read the
same data throughout the transaction. The bad news is there is a greater
chance of deadlock. Each connection has a shared lock on the row in the
Employee table, and wants an exclusive lock. Neither can get the exclusive
lock because the other has the shared lock, so you have deadlock.
One of the first suggestions we give to try to reduce deadlock is to reduce
your isolation level; in this case, bring it back to read committed.
Another solution here would be to use an UPDLOCK hint when you do the
select. Then the first process would get an update lock, not a shared lock,
and when the second process tried to get the update lock, it would be
blocked. The first process could then get the exclusive lock and do the
update operation, and finish the transaction. Then the second process could
get first the update lock, then the exclusive lock, and then finish, with no
deadlock occurring.
--
HTH
Kalen Delaney, SQL Server MVP
www.solidqualitylearning.com
"Amos Soma" <amos_j_soma@.yahoo.com> wrote in message
news:%23$22cVEKGHA.3960@.TK2MSFTNGP09.phx.gbl...
> If I understand correctly, when using a Read Committed isolation level,
> the most common reason for a deadlock is because two processes update a
> set of tables in different order. However, it seems that when using a
> Repeatable Read isolation level, the odds of a deadlock increase
> significantly.
> For example, open Management Studio and create two different connections
> against the AdventureWorks database. In both connections execute the
> following:
> SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
> Begin Tran
> SELECT EmployeeID From HumanResources.Employee Where EmployeeID = 1
>
> Then, in the first connection execute the following (but do not commit the
> transaction):
> Update HumanResources.Employee Set MaritalStatus = 'M' Where EmployeeID => 1
> In the second connection execute the exact same line. This will cause a
> deadlock error in the second connection. We get a deadlock even though
> both processes are performing the exact same action in the exact same
> order.
> This example may not be the best but is my assumption correct that when
> using Repeatable Read, the likelihood of a deadlock error is greater than
> when using Read Committed?
> Thanks, Amos.
>
>

Deadlocks & Transaction Isolation Level

If I understand correctly, when using a Read Committed isolation level, the
most common reason for a deadlock is because two processes update a set of
tables in different order. However, it seems that when using a Repeatable
Read isolation level, the odds of a deadlock increase significantly.
For example, open Management Studio and create two different connections
against the AdventureWorks database. In both connections execute the
following:
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Begin Tran
SELECT EmployeeID From HumanResources.Employee Where EmployeeID = 1
Then, in the first connection execute the following (but do not commit the
transaction):
Update HumanResources.Employee Set MaritalStatus = 'M' Where EmployeeID = 1
In the second connection execute the exact same line. This will cause a
deadlock error in the second connection. We get a deadlock even though both
processes are performing the exact same action in the exact same order.
This example may not be the best but is my assumption correct that when
using Repeatable Read, the likelihood of a deadlock error is greater than
when using Read Committed?
Thanks, Amos.> when using a Read Committed isolation level, the
> most common reason for a deadlock is because two processes
> update a set of tables in different order.
not exactly. 2 processses may update rows in only one table and still
clinch in a deadlock.|||Hi Amos
Yes, your understanding is correct. Using a higher isolation level like
repeatable read has tradeoffs.
In read committed the locks on the SELECT would be released as soon as the
SELECT was finished. In repeatable read, the SELECT (shared) locks are not
released. The good news is that each transaction is guaranteed to read the
same data throughout the transaction. The bad news is there is a greater
chance of deadlock. Each connection has a shared lock on the row in the
Employee table, and wants an exclusive lock. Neither can get the exclusive
lock because the other has the shared lock, so you have deadlock.
One of the first suggestions we give to try to reduce deadlock is to reduce
your isolation level; in this case, bring it back to read committed.
Another solution here would be to use an UPDLOCK hint when you do the
select. Then the first process would get an update lock, not a shared lock,
and when the second process tried to get the update lock, it would be
blocked. The first process could then get the exclusive lock and do the
update operation, and finish the transaction. Then the second process could
get first the update lock, then the exclusive lock, and then finish, with no
deadlock occurring.
HTH
Kalen Delaney, SQL Server MVP
www.solidqualitylearning.com
"Amos Soma" <amos_j_soma@.yahoo.com> wrote in message
news:%23$22cVEKGHA.3960@.TK2MSFTNGP09.phx.gbl...
> If I understand correctly, when using a Read Committed isolation level,
> the most common reason for a deadlock is because two processes update a
> set of tables in different order. However, it seems that when using a
> Repeatable Read isolation level, the odds of a deadlock increase
> significantly.
> For example, open Management Studio and create two different connections
> against the AdventureWorks database. In both connections execute the
> following:
> SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
> Begin Tran
> SELECT EmployeeID From HumanResources.Employee Where EmployeeID = 1
>
> Then, in the first connection execute the following (but do not commit the
> transaction):
> Update HumanResources.Employee Set MaritalStatus = 'M' Where EmployeeID =
> 1
> In the second connection execute the exact same line. This will cause a
> deadlock error in the second connection. We get a deadlock even though
> both processes are performing the exact same action in the exact same
> order.
> This example may not be the best but is my assumption correct that when
> using Repeatable Read, the likelihood of a deadlock error is greater than
> when using Read Committed?
> Thanks, Amos.
>
>

Sunday, March 25, 2012

deadlock with replication's update/insert/delete process

We are using SQL 2K with sp4. We are using Push method and both publisher
and distribution db are on the same server.
Recently we have quite a few deadlocks involving a replication's sp such as
sp_MSupd_xxxxxxx and some select statement from our application. We have
deadlocks from time to time but I haven't seen a deadlock caused by sp_MSupd
until now. Is this an indication of something that I need to look into?
Any help is very much appreciated.
Wingman
Sounds like a transaction on the publisher is coming over as a transaction
on the subscriber which you're deadlocking with. Some ideas: you could look
at the order of the transaction on the publisher and check that your
application accesses tables in the same order. You could allow your
application to do dirty reads (not generally recommended but sometimes
useful). You could use SQL Server 2005 and the snapshot isolation level
where this problem goes away. Finally you could control when the
distribution agent runs to avoid the lcash.
Cheers,
Paul Ibison SQL Server MVP, www.replicationanswers.com .

Thursday, March 22, 2012

Deadlock question

I have general question about deadlocks. I get the occasional deadlock when
someone attempts to update a row in the data. I think this might be caused
because the update is happening at the exact same time the row in question
is being updated by a trigger on another table - that I have no control
over.
I'm not sure in general terms how to resolve an issue like this. I'm almost
thinking I should retry the insert immediately if it fails - this is the
only reason it ever fails. But I'm sure mentioning that will get me flamed
so I'm open to ideas from the experts.
Any advice is appreciated.
Jason
I can't agree with your reasoning, as it should be possible on a multi-user
system. The following pages from SQL Server 2000 Books Online, should get
you started in the right direction.
Deadlocking
Handling Deadlocks
Minimizing Deadlocks
Detecting and Ending Deadlocks
HTH,
Vyas, MVP (SQL Server)
http://vyaskn.tripod.com/
Is .NET important for a database professional?
http://vyaskn.tripod.com/poll.htm
"Jason MacKenzie" <jmackenzie_nospam@.formet.com> wrote in message
news:uEuOcIeMEHA.3556@.TK2MSFTNGP09.phx.gbl...
I have general question about deadlocks. I get the occasional deadlock when
someone attempts to update a row in the data. I think this might be caused
because the update is happening at the exact same time the row in question
is being updated by a trigger on another table - that I have no control
over.
I'm not sure in general terms how to resolve an issue like this. I'm almost
thinking I should retry the insert immediately if it fails - this is the
only reason it ever fails. But I'm sure mentioning that will get me flamed
so I'm open to ideas from the experts.
Any advice is appreciated.
Jason
|||I have no reasoning. But I appreciate your response and will take a look at
those articles.
"Narayana Vyas Kondreddi" <answer_me@.hotmail.com> wrote in message
news:%23nACcUeMEHA.3400@.TK2MSFTNGP09.phx.gbl...
> I can't agree with your reasoning, as it should be possible on a
multi-user
> system. The following pages from SQL Server 2000 Books Online, should get
> you started in the right direction.
> Deadlocking
> Handling Deadlocks
> Minimizing Deadlocks
> Detecting and Ending Deadlocks
> --
> HTH,
> Vyas, MVP (SQL Server)
> http://vyaskn.tripod.com/
> Is .NET important for a database professional?
> http://vyaskn.tripod.com/poll.htm
>
> "Jason MacKenzie" <jmackenzie_nospam@.formet.com> wrote in message
> news:uEuOcIeMEHA.3556@.TK2MSFTNGP09.phx.gbl...
> I have general question about deadlocks. I get the occasional deadlock
when
> someone attempts to update a row in the data. I think this might be caused
> because the update is happening at the exact same time the row in question
> is being updated by a trigger on another table - that I have no control
> over.
> I'm not sure in general terms how to resolve an issue like this. I'm
almost
> thinking I should retry the insert immediately if it fails - this is the
> only reason it ever fails. But I'm sure mentioning that will get me flamed
> so I'm open to ideas from the experts.
> Any advice is appreciated.
> Jason
>
>

Deadlock question

I have general question about deadlocks. I get the occasional deadlock when
someone attempts to update a row in the data. I think this might be caused
because the update is happening at the exact same time the row in question
is being updated by a trigger on another table - that I have no control
over.
I'm not sure in general terms how to resolve an issue like this. I'm almost
thinking I should retry the insert immediately if it fails - this is the
only reason it ever fails. But I'm sure mentioning that will get me flamed
so I'm open to ideas from the experts.
Any advice is appreciated.
JasonI can't agree with your reasoning, as it should be possible on a multi-user
system. The following pages from SQL Server 2000 Books Online, should get
you started in the right direction.
Deadlocking
Handling Deadlocks
Minimizing Deadlocks
Detecting and Ending Deadlocks
--
HTH,
Vyas, MVP (SQL Server)
http://vyaskn.tripod.com/
Is .NET important for a database professional?
http://vyaskn.tripod.com/poll.htm
"Jason MacKenzie" <jmackenzie_nospam@.formet.com> wrote in message
news:uEuOcIeMEHA.3556@.TK2MSFTNGP09.phx.gbl...
I have general question about deadlocks. I get the occasional deadlock when
someone attempts to update a row in the data. I think this might be caused
because the update is happening at the exact same time the row in question
is being updated by a trigger on another table - that I have no control
over.
I'm not sure in general terms how to resolve an issue like this. I'm almost
thinking I should retry the insert immediately if it fails - this is the
only reason it ever fails. But I'm sure mentioning that will get me flamed
so I'm open to ideas from the experts.
Any advice is appreciated.
Jason|||I have no reasoning. But I appreciate your response and will take a look at
those articles.
"Narayana Vyas Kondreddi" <answer_me@.hotmail.com> wrote in message
news:%23nACcUeMEHA.3400@.TK2MSFTNGP09.phx.gbl...
> I can't agree with your reasoning, as it should be possible on a
multi-user
> system. The following pages from SQL Server 2000 Books Online, should get
> you started in the right direction.
> Deadlocking
> Handling Deadlocks
> Minimizing Deadlocks
> Detecting and Ending Deadlocks
> --
> HTH,
> Vyas, MVP (SQL Server)
> http://vyaskn.tripod.com/
> Is .NET important for a database professional?
> http://vyaskn.tripod.com/poll.htm
>
> "Jason MacKenzie" <jmackenzie_nospam@.formet.com> wrote in message
> news:uEuOcIeMEHA.3556@.TK2MSFTNGP09.phx.gbl...
> I have general question about deadlocks. I get the occasional deadlock
when
> someone attempts to update a row in the data. I think this might be caused
> because the update is happening at the exact same time the row in question
> is being updated by a trigger on another table - that I have no control
> over.
> I'm not sure in general terms how to resolve an issue like this. I'm
almost
> thinking I should retry the insert immediately if it fails - this is the
> only reason it ever fails. But I'm sure mentioning that will get me flamed
> so I'm open to ideas from the experts.
> Any advice is appreciated.
> Jason
>
>

Deadlock question

I have general question about deadlocks. I get the occasional deadlock when
someone attempts to update a row in the data. I think this might be caused
because the update is happening at the exact same time the row in question
is being updated by a trigger on another table - that I have no control
over.
I'm not sure in general terms how to resolve an issue like this. I'm almost
thinking I should retry the insert immediately if it fails - this is the
only reason it ever fails. But I'm sure mentioning that will get me flamed
so I'm open to ideas from the experts.
Any advice is appreciated.
JasonI can't agree with your reasoning, as it should be possible on a multi-user
system. The following pages from SQL Server 2000 Books Online, should get
you started in the right direction.
Deadlocking
Handling Deadlocks
Minimizing Deadlocks
Detecting and Ending Deadlocks
--
HTH,
Vyas, MVP (SQL Server)
http://vyaskn.tripod.com/
Is .NET important for a database professional?
http://vyaskn.tripod.com/poll.htm
"Jason MacKenzie" <jmackenzie_nospam@.formet.com> wrote in message
news:uEuOcIeMEHA.3556@.TK2MSFTNGP09.phx.gbl...
I have general question about deadlocks. I get the occasional deadlock when
someone attempts to update a row in the data. I think this might be caused
because the update is happening at the exact same time the row in question
is being updated by a trigger on another table - that I have no control
over.
I'm not sure in general terms how to resolve an issue like this. I'm almost
thinking I should retry the insert immediately if it fails - this is the
only reason it ever fails. But I'm sure mentioning that will get me flamed
so I'm open to ideas from the experts.
Any advice is appreciated.
Jason|||I have no reasoning. But I appreciate your response and will take a look at
those articles.
"Narayana Vyas Kondreddi" <answer_me@.hotmail.com> wrote in message
news:%23nACcUeMEHA.3400@.TK2MSFTNGP09.phx.gbl...
> I can't agree with your reasoning, as it should be possible on a
multi-user
> system. The following pages from SQL Server 2000 Books Online, should get
> you started in the right direction.
> Deadlocking
> Handling Deadlocks
> Minimizing Deadlocks
> Detecting and Ending Deadlocks
> --
> HTH,
> Vyas, MVP (SQL Server)
> http://vyaskn.tripod.com/
> Is .NET important for a database professional?
> http://vyaskn.tripod.com/poll.htm
>
> "Jason MacKenzie" <jmackenzie_nospam@.formet.com> wrote in message
> news:uEuOcIeMEHA.3556@.TK2MSFTNGP09.phx.gbl...
> I have general question about deadlocks. I get the occasional deadlock
when
> someone attempts to update a row in the data. I think this might be caused
> because the update is happening at the exact same time the row in question
> is being updated by a trigger on another table - that I have no control
> over.
> I'm not sure in general terms how to resolve an issue like this. I'm
almost
> thinking I should retry the insert immediately if it fails - this is the
> only reason it ever fails. But I'm sure mentioning that will get me flamed
> so I'm open to ideas from the experts.
> Any advice is appreciated.
> Jason
>
>sql

Wednesday, March 21, 2012

Deadlock on Update using temp table

I sometimes get the following error from an update statement in a
stored procedure:

Transaction (Process ID 62) was deadlocked on thread | communication
buffer resources with another process and has been chosen as the
deadlock victim. Rerun the transaction.

The isolation level is READ UNCOMMITTED and there are no explicit
transactions in the stored procedure. The update statement is as
follows:

UPDATE PL
SET PL.PL_SI_LAST_YEAR_AMOUNT = #tmpWorkPLPrior.PRIOR_AMOUNT
FROM #tmpWorkPLPrior
WHERE PL.COMPANY = @.comp
AND PL.PLAN_YEAR = @.year
AND PL.FORECAST_QUARTER = @.qtr
AND PL.VERSION_ID = @.ver
AND PL.BUSINESS_UNIT_CODE = #tmpWorkPLPrior.BUSINESS_UNIT
AND PL.PROJECT_ID = #tmpWorkPLPrior.PROJECT_ID
AND PL.BUDGET_CODE = #tmpWorkPLPrior.BUDGET_CODE
AND PL.BUSINESS_UNIT_CODE <> 'G7'

PL rows: 24,342,553
PL rows - Filtered: 230,088
#tmpWorkPLPrior rows: 3,641
Updated rows: 43,692

The temp table (#tmpWorkPLPrior) is created by a SELECT INTO statement.
It has the values that need to be set in the PL table. The PL table
has a clustered index on 8 columns. The filters (@.comp, @.year, ...)
select 230,088 rows. When the update succeeds it updates 43,692 rows
in about 15 seconds. Why does this sometimes deadlock and other times
succeed? There is nothing else running, so the process is deadlocking
on itself.

Thanks,
FrankHi Frank

I don't have the skills and time to analyse your specific issue, but I
hope this general link could help you:
SQL Server technical bulletin - How to resolve a deadlock:
http://support.microsoft.com/kb/832524/en-us

Cheers
SMF|||Hi

You don't give the version of SQL Server you are running?

In general it is better to create the temporary table separately.

Heavy use of tempdb may be helped by moving it to it's own drive(s) and
using multiple files see
http://support.microsoft.com/defaul...kb;en-us;328551

Also check out http://support.microsoft.com/kb/271509/EN-US/ and
http://support.microsoft.com/kb/224453/EN-US/ on how to identify blocking.

John

<fmatamoros@.yahoo.com> wrote in message
news:1135823370.065365.186970@.g44g2000cwa.googlegr oups.com...
>I sometimes get the following error from an update statement in a
> stored procedure:
> Transaction (Process ID 62) was deadlocked on thread | communication
> buffer resources with another process and has been chosen as the
> deadlock victim. Rerun the transaction.
> The isolation level is READ UNCOMMITTED and there are no explicit
> transactions in the stored procedure. The update statement is as
> follows:
> UPDATE PL
> SET PL.PL_SI_LAST_YEAR_AMOUNT = #tmpWorkPLPrior.PRIOR_AMOUNT
> FROM #tmpWorkPLPrior
> WHERE PL.COMPANY = @.comp
> AND PL.PLAN_YEAR = @.year
> AND PL.FORECAST_QUARTER = @.qtr
> AND PL.VERSION_ID = @.ver
> AND PL.BUSINESS_UNIT_CODE = #tmpWorkPLPrior.BUSINESS_UNIT
> AND PL.PROJECT_ID = #tmpWorkPLPrior.PROJECT_ID
> AND PL.BUDGET_CODE = #tmpWorkPLPrior.BUDGET_CODE
> AND PL.BUSINESS_UNIT_CODE <> 'G7'
> PL rows: 24,342,553
> PL rows - Filtered: 230,088
> #tmpWorkPLPrior rows: 3,641
> Updated rows: 43,692
> The temp table (#tmpWorkPLPrior) is created by a SELECT INTO statement.
> It has the values that need to be set in the PL table. The PL table
> has a clustered index on 8 columns. The filters (@.comp, @.year, ...)
> select 230,088 rows. When the update succeeds it updates 43,692 rows
> in about 15 seconds. Why does this sometimes deadlock and other times
> succeed? There is nothing else running, so the process is deadlocking
> on itself.
> Thanks,
> Frank|||Hi,

Don't get distracted, the temporary table is not causing your deadlock,
rather the update on PL is.

Its feasible that your connection is locking index pages, data pages that
other connections also have locked before you grab them - you are updating
quite a lot of rows in one go so the transaction will be quite large.

Have you checked the query plan for this UPDATE? Index on some of the
columns in your WHERE clause will help reduce the IO.

READ UNCOMMITTED is redundant on the UPDATE - the locks will be placed
because you are updating the data, you could use READ UNCOMMITTED on ALL
your readers and that would help.

I don't tend to use such large composite keys like this, I would use a
surrogate - 'ID' integer column instead and update by joining using that (if
thats possible in your case).

Reading your end bit, if you are absolutely sure that nothing else is
accessing that table then the plan is probably deadlocking itself because of
parallelism which can happen, you can stop parallelism by using MAXDOP 1 on
the OPTIONS clause of the UPDATE statement.

Hope that helps.

--
Tony Rogerson
SQL Server MVP
http://sqlserverfaq.com - free video tutorials

<fmatamoros@.yahoo.com> wrote in message
news:1135823370.065365.186970@.g44g2000cwa.googlegr oups.com...
>I sometimes get the following error from an update statement in a
> stored procedure:
> Transaction (Process ID 62) was deadlocked on thread | communication
> buffer resources with another process and has been chosen as the
> deadlock victim. Rerun the transaction.
> The isolation level is READ UNCOMMITTED and there are no explicit
> transactions in the stored procedure. The update statement is as
> follows:
> UPDATE PL
> SET PL.PL_SI_LAST_YEAR_AMOUNT = #tmpWorkPLPrior.PRIOR_AMOUNT
> FROM #tmpWorkPLPrior
> WHERE PL.COMPANY = @.comp
> AND PL.PLAN_YEAR = @.year
> AND PL.FORECAST_QUARTER = @.qtr
> AND PL.VERSION_ID = @.ver
> AND PL.BUSINESS_UNIT_CODE = #tmpWorkPLPrior.BUSINESS_UNIT
> AND PL.PROJECT_ID = #tmpWorkPLPrior.PROJECT_ID
> AND PL.BUDGET_CODE = #tmpWorkPLPrior.BUDGET_CODE
> AND PL.BUSINESS_UNIT_CODE <> 'G7'
> PL rows: 24,342,553
> PL rows - Filtered: 230,088
> #tmpWorkPLPrior rows: 3,641
> Updated rows: 43,692
> The temp table (#tmpWorkPLPrior) is created by a SELECT INTO statement.
> It has the values that need to be set in the PL table. The PL table
> has a clustered index on 8 columns. The filters (@.comp, @.year, ...)
> select 230,088 rows. When the update succeeds it updates 43,692 rows
> in about 15 seconds. Why does this sometimes deadlock and other times
> succeed? There is nothing else running, so the process is deadlocking
> on itself.
> Thanks,
> Frank|||Using MAXDOP 1 on the OPTIONS clause seems to fix my deadlock problem.

Thanks,
Frank

Deadlock on Update Statement (NOLOCK)

I have the following updates statements in my stored procedure which caused
a deadlock. Should I take the (NOLOCK) statement out of the update
statements?
Is there some else I can to help resolve this deadlock?
Thanks,
Update SRA_FlowMaster
Set Status = 'I'
From SRA_FlowMaster New
Inner Join SRA_FlowMaster (NoLock)
On New. FlowMasterNo = SRA_FlowMaster. FlowMasterNo
And New.TypeCode = SRA_FlowMaster. TypeCode
WhereNew. FlowMasterID = @.i_FlowMasterID
And SRA_FlowMaster. FlowMasterID <> @.i_FlowMasterID
And SRA_FlowMaster. Status In ('K', 'M')
Update SRA_FlowMaster
Set Status = 'I'
From SRA_FlowMaster New
Inner Join SRA_FlowMaster (NoLock)
On New. FlowMasterNo = SRA_FlowMaster. FlowMaster
And New.TypeCode = SRA_FlowMaster. TypeCode
Where New. FlowMasterID = @.i_FlowMasterID
And SRA_FlowMaster. FlowMasterID <> @.i_FlowMasterID
And SRA_FlowMaster. Status = 'A'
And New. Status In ('A', 'D')Joe,
A deadlock involved two processes requesting a resource being locked by the
other. You have to identify the processes and the statements causing the
deadlock. The table hint you are using is not a hint to prevent deadlocks.
See "Minimizing Deadlocks" and "Troubleshooting Deadlocks" in BOL for more
information.
Tracing Deadlocks
http://www.sqlservercentral.com/col...ngdeadlocks.asp
AMB
"Joe K." wrote:

> I have the following updates statements in my stored procedure which cause
d
> a deadlock. Should I take the (NOLOCK) statement out of the update
> statements?
> Is there some else I can to help resolve this deadlock?
> Thanks,
>
> Update SRA_FlowMaster
> Set Status = 'I'
> From SRA_FlowMaster New
> Inner Join SRA_FlowMaster (NoLock)
> On New. FlowMasterNo = SRA_FlowMaster. FlowMasterNo
> And New.TypeCode = SRA_FlowMaster. TypeCode
> WhereNew. FlowMasterID = @.i_FlowMasterID
> And SRA_FlowMaster. FlowMasterID <> @.i_FlowMasterID
> And SRA_FlowMaster. Status In ('K', 'M')
> Update SRA_FlowMaster
> Set Status = 'I'
> From SRA_FlowMaster New
> Inner Join SRA_FlowMaster (NoLock)
> On New. FlowMasterNo = SRA_FlowMaster. FlowMaster
> And New.TypeCode = SRA_FlowMaster. TypeCode
> Where New. FlowMasterID = @.i_FlowMasterID
> And SRA_FlowMaster. FlowMasterID <> @.i_FlowMasterID
> And SRA_FlowMaster. Status = 'A'
> And New. Status In ('A', 'D')
>|||Hmm. Let me guess.
'Status' has only a handful of values.
You have an index on 'Status'.
Almost all of the values of 'Status' are the same.
This is a pretty common issue. Status fields are really a bad way to
represent and control status of an object, even thought they seem intuitive
at first. The key range locking required on an update makes it almost
impossible to scale to any reasonable level.
You can drop the index on Status but you will probably time out on some
other queries. (NOLOCK) hints won't change the inherent locking required to
do an update. Your problem is architectural and will require adjusting the
schema to fix. I would represent Status as a work queue using another
table. The presence of a pointer to the Primary Key indicates the status.
If there is no entries, then the status is whatever the most common status
(I.E. 'Closed', 'C', 'Paid', depending on the context) actually is.
Geoff N. Hiten
Microsoft SQL Server MVP
"Joe K." <Joe K.@.discussions.microsoft.com> wrote in message
news:BED3489D-5AC1-48A7-B785-C9EF6128573B@.microsoft.com...
> I have the following updates statements in my stored procedure which
> caused
> a deadlock. Should I take the (NOLOCK) statement out of the update
> statements?
> Is there some else I can to help resolve this deadlock?
> Thanks,
>
> Update SRA_FlowMaster
> Set Status = 'I'
> From SRA_FlowMaster New
> Inner Join SRA_FlowMaster (NoLock)
> On New. FlowMasterNo = SRA_FlowMaster. FlowMasterNo
> And New.TypeCode = SRA_FlowMaster. TypeCode
> WhereNew. FlowMasterID = @.i_FlowMasterID
> And SRA_FlowMaster. FlowMasterID <> @.i_FlowMasterID
> And SRA_FlowMaster. Status In ('K', 'M')
> Update SRA_FlowMaster
> Set Status = 'I'
> From SRA_FlowMaster New
> Inner Join SRA_FlowMaster (NoLock)
> On New. FlowMasterNo = SRA_FlowMaster. FlowMaster
> And New.TypeCode = SRA_FlowMaster. TypeCode
> Where New. FlowMasterID = @.i_FlowMasterID
> And SRA_FlowMaster. FlowMasterID <> @.i_FlowMasterID
> And SRA_FlowMaster. Status = 'A'
> And New. Status In ('A', 'D')
>

Deadlock on simple update related to clustered index

I am encountering a deadlock situation, with two threads
running two updates to the same table, if that table has a
clustered index on it that is NOT the primary key, and the
where clause of the UPDATE statement is on the primary
key. Very strange... Here is the test case:
create table x
(id int not null,
lastModified datetime not null,
altkey varchar(3) not null)
GO
CREATE UNIQUE CLUSTERED INDEX IAK_X ON x (altKey)
GO
alter table x add constraint pk_x primary key(id)
GO
insert into x
values (1, getdate(), 'XXX');
Then, from 2 ISQL threads, ran the following code...
begin tran
waitfor time '15:06' -- ensure they start at same time
update x
set lastModified = getdate()
where id = 1;
waitfor delay '000:00:10' -- wait to ensure lock occurs
update x
set lastModified = getdate()
where id = 1;
commit tran;
When I monitor the locks, the following happens:
Thread A successfully performs Update 1
Thread B is blocked as A has Exclusive lock on the row.
Thread B, however, successfully gets a KEY UPDATE lock on
PK_X
Thread A, when it tries to perform Update 2, is blocked
trying to get a KEY UPDATE lock on PK_X, causing the
deadlock.
Even if I then drop the clustered index with
DROP INDEX x.iak_x;
the problem remains.
However, if I NEVER create the clustered index. The
threads both work fine and never encounter a deadlock.
Neither transaction attempts to get a KEY UPDATE lock on
the primary key index PK_X.
We try to use clustered indexes on fields other than the
ID # (one-up number, but NOT an IDENTITY column in this
case), because we encountered deadlocks on Inserts in the
past.
Any help would be greatly appreciated.On Thu, 24 Jul 2003 14:02:58 -0700, "Corey" <chorton1@.austin.rr.com>
wrote:
>Any help would be greatly appreciated.
That's pretty humorous.
I've never gotten into the detailed guts of SQLServer like some around
here, but it sounds to me like you've hit a SQLServer bug. It looks
like SQLServer locks the data record in thread A, but allows thread B
to begin and get a lock on an index entry while waiting for the data,
and voila, deadlock. If that is the case, I'd call it a bug.
I assume it works correctly if you have the PK on id?
J.sql

Deadlock on replication update and NOLOCK hint question

Hi all,
I have an interesting situation. We have the following scenario:
1. Server A, Database A, table A as the replication publisher
2. Server B, Database B, table B as the replication subscriber.
3. Server B, Database C
Database A was replicating an update to Server B, Database B, table
B
At the same time, a stored procedure on Server B, Database C attempted
to perform the following type of query on Server B, Database B, table
B:
insert into table B
select ...
from database D (NOLOCK)
inner join other tables all with (NOLOCK) hints
Server B, Database C's stored procedure was the deadlock victim.
My understanding of a deadlock is when two queries are competing for
the same resources and the resource with the least cost or work done
is the victim.
I would think that the NOLOCK hint would not allow Server B, Database
C's stored proc to hold resources and therefore I could see blocking
occuring with the replication update but not deadlocking since I would
think that NOLOCK would not hold on to resources.
Could the insert select with the NOLOCK have held a page lock that
caused it to hold the same resources that the update replication
statement needed and vice-versa?
Btw, I am aware of the dirty reads for the NOLOCK statements and we
use them for business purposes for our DML statements.
Any ideas would be helpful.
Thanks in advance!Hi,
I suggest you try out the tool called SQL Deadlock Detector. It monitors
your database for locks and deadlocks and provides complete information on
captured events. It tells you everything you need to know (locked objects,
blocked statements, blocking statements, etc.) to solve your
blocking/deadlock problems. The great thing about this tool is it's event
diagram which makes it exremely easy to see what exactly is going on.
You can download it from here:
http://lakesidesql.com/downloads/DLD2/2_0_2007_809/DeadlockDetector2_Setup_08-09-2007.zip.
HTH.
"techgrl" <lfischmar@.yahoo.com> wrote in message
news:1188404072.124101.68920@.k79g2000hse.googlegroups.com...
> Hi all,
> I have an interesting situation. We have the following scenario:
> 1. Server A, Database A, table A as the replication publisher
> 2. Server B, Database B, table B as the replication subscriber.
> 3. Server B, Database C
> Database A was replicating an update to Server B, Database B, table
> B
> At the same time, a stored procedure on Server B, Database C attempted
> to perform the following type of query on Server B, Database B, table
> B:
> insert into table B
> select ...
> from database D (NOLOCK)
> inner join other tables all with (NOLOCK) hints
>
> Server B, Database C's stored procedure was the deadlock victim.
> My understanding of a deadlock is when two queries are competing for
> the same resources and the resource with the least cost or work done
> is the victim.
> I would think that the NOLOCK hint would not allow Server B, Database
> C's stored proc to hold resources and therefore I could see blocking
> occuring with the replication update but not deadlocking since I would
> think that NOLOCK would not hold on to resources.
> Could the insert select with the NOLOCK have held a page lock that
> caused it to hold the same resources that the update replication
> statement needed and vice-versa?
> Btw, I am aware of the dirty reads for the NOLOCK statements and we
> use them for business purposes for our DML statements.
> Any ideas would be helpful.
> Thanks in advance!
>|||Hi,
I suggest you try out the tool called SQL Deadlock Detector. It monitors
your database for locks and deadlocks and provides complete information on
captured events. It tells you everything you need to know (locked objects,
blocked statements, blocking statements, etc.) to solve your
blocking/deadlock problems. The great thing about this tool is it's event
diagram which makes it exremely easy to see what exactly is going on.
You can download it from here:
http://lakesidesql.com/downloads/DLD2/2_0_2007_809/DeadlockDetector2_Setup_08-09-2007.zip.
HTH.
"techgrl" <lfischmar@.yahoo.com> wrote in message
news:1188404072.124101.68920@.k79g2000hse.googlegroups.com...
> Hi all,
> I have an interesting situation. We have the following scenario:
> 1. Server A, Database A, table A as the replication publisher
> 2. Server B, Database B, table B as the replication subscriber.
> 3. Server B, Database C
> Database A was replicating an update to Server B, Database B, table
> B
> At the same time, a stored procedure on Server B, Database C attempted
> to perform the following type of query on Server B, Database B, table
> B:
> insert into table B
> select ...
> from database D (NOLOCK)
> inner join other tables all with (NOLOCK) hints
>
> Server B, Database C's stored procedure was the deadlock victim.
> My understanding of a deadlock is when two queries are competing for
> the same resources and the resource with the least cost or work done
> is the victim.
> I would think that the NOLOCK hint would not allow Server B, Database
> C's stored proc to hold resources and therefore I could see blocking
> occuring with the replication update but not deadlocking since I would
> think that NOLOCK would not hold on to resources.
> Could the insert select with the NOLOCK have held a page lock that
> caused it to hold the same resources that the update replication
> statement needed and vice-versa?
> Btw, I am aware of the dirty reads for the NOLOCK statements and we
> use them for business purposes for our DML statements.
> Any ideas would be helpful.
> Thanks in advance!
>

Sunday, March 11, 2012

deadlock between select (shared) and update (intent exclusive)

I regularly have deadlocks on my sql-server 2000. Using the 1204 trace
I got the following info about the problem:
Wait-for graph
Node:1
PAG: 7:1:251381 CleanCnt:2 Mode: S Flags: 0x2
Grant List 0::
Owner:0x2c959e00 Mode: S Flg:0x0 Ref:1 Life:00000000 SPID:61
ECID:3
Requested By:
ResType:LockOwner Stype:'OR' Mode: IX SPID:72 ECID:0 Ec0x50871568)
Value:0x76375e60 Cost0/5580)
Node:2
PAG: 7:1:230822 CleanCnt:2 Mode: IX Flags: 0x2
Grant List 3::
Owner:0x4bba49e0 Mode: IX Flg:0x0 Ref:1 Life:02000000 SPID:72
ECID:0
SPID: 72 ECID: 0 Statement Type: INSERT Line #: 1
Input Buf: RPC Event: sp_executesql;1
Requested By:
ResType:LockOwner Stype:'OR' Mode: S SPID:61 ECID:3 Ec0x2D8EA0C0)
Value:0x75df1780 Cost0/0)
Victim Resource Owner:
ResType:LockOwner Stype:'OR' Mode: S SPID:61 ECID:3 Ec0x2D8EA0C0)
Value:0x75df1780 Cost0/0)
As I understand it, one statement owns an IX-lock and requests another
one while another statement owns a shared-lock and requests another
one. I know, I should always access tables in the same order but it's
too late for this now.
How can I tell the select statement to read the last commited data and
not to lock anything? IMHO we did not give any lock-hints with our
statements so the default lock levels should be used. Does it make
sense that a select blocks an update?Update: it is not a select and an UPDATE but a select count and an
insert.|||
> As I understand it, one statement owns an IX-lock and requests another
> one while another statement owns a shared-lock and requests another
> one. I know, I should always access tables in the same order but it's
> too late for this now.
> How can I tell the select statement to read the last commited data and
> not to lock anything? IMHO we did not give any lock-hints with our
> statements so the default lock levels should be used. Does it make
> sense that a select blocks an update?
>
I do not pretend to understand your locking situation.
And although I thought in the past that a select should Not be partner
in a deadlock. This proved to be wrong.
My situation.
Update transaction (standard isolation), two updates on one single row.
The select was a very simple select which resulted in a single row of a
single table.
The combination could result in a deadlock.
The probable cause of 'my' problem.
Both updates used different where clauses, which resulted in the same row,
but
resulted in different locking situations.
In this situation you can NOT tel to read the last commited data, because
that is
locked at the moment. In SQL-server 2005 you can opt for snapshot isolation,
where the last commited data is read. So with snapshot isolation reads do
not block
write and writes do not block reads.
Be carefull with snapshot isolation because this does not implement
serializability.
Good luck with your situation,
If you have more information please post it here,
If you have more questions please post it here.
ben brugman|||mhuhn.de@.gmail.com,
This feature has been implemented in SQL Server 2005 (Snapshot Isolation).
If you are using 2000 and do not want to change the order in which you
access your tables, consider using a table_hint in your "select" statement,
specifically ROWLOCK based on the info you posted (the lock seems to be at
the page level). See BOL for more info.
AMB
"mhuhn.de@.gmail.com" wrote:

> Update: it is not a select and an UPDATE but a select count and an
> insert.
>|||Thanks for answering. Anyway, 2005 is not an option because our
solution is already used from lots of customers. Do you think a ROWLOCK
makes sense if I do a select count? If the where-clause in the select
count includes the updated row, I'll have the same problem, right?
Furthermore, it will slow down my selects!?|||As I wrote in my other mail :
I do not pretend to understand your locking situation.
But I doubt very much that a ROWLOCK in the select will
solve the problem. The select (without a rowlock) is allready
waiting for another process to finish, this waiting can (I think)
not be solved by using a ROWLOCK, the rowlock will
(probably) prevent the other process on locking on the read
process.
A (row)lock in the update might claim enough resources that
the select is not capable of applying a lock which can stop the
update. So the update can finish after which the select can finish.
ben brugman
<mhuhn.de@.gmail.com> wrote in message
news:1147960900.879319.169740@.j55g2000cwa.googlegroups.com...
> Thanks for answering. Anyway, 2005 is not an option because our
> solution is already used from lots of customers. Do you think a ROWLOCK
> makes sense if I do a select count? If the where-clause in the select
> count includes the updated row, I'll have the same problem, right?
> Furthermore, it will slow down my selects!?
>

Deadlock at trigger


a trigger need to insert or update record at the other table in high traffic environments
however, the deadlock happens; ie, a trigger running twice at the same time want to need to insert record at the table.

i trid to change isolation as SERIALIZABLE or REPEATABLE , but i cannot solve the problem. i guess the "while loop" affects the result because i try to cancel the loop and execute smoothly.

? How to solve the deadlock?
Thx

--
i used the following commands to change isolation level:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
begin transaction
commit transaction

--
the code are as follows:
declare setskuCursor cursor
local
static
for select item, quantity from invset where sku = @.sku
open setskuCursor
fetch next from setskuCursor into @.invsetitem, @.invsetqty
while @.@.fetch_status = 0
begin

select @.balsku = sku, @.opendate = opendate from invbal where sku = @.invsetitem
if (@.balsku is not null)
begin
if @.txdate <= @.opendate
update invbal set slsqtynow = slsqtynow + @.itmtxqty * @.invsetqty where sku = @.invsetitem
if @.txdate > @.opendate
update invbal set slsqtynxt = slsqtynxt + @.itmtxqty * @.invsetqty where sku = @.invsetitem
end
else
begin

INSERT INTO INVBAL (SHOP, SKU, OPENDATE, SLSQTYNOW) VALUES (@.shop, @.invsetitem, @.bizdate, @.itmtxqty * @.invsetqty)

end
fetch next from setskuCursor into @.invsetitem, @.invsetqty
end
close setskuCursor
deallocate setskuCursor
-

Use (NOLOCK) on all SELECT...

select item, quantity from invset (NOLOCK) where sku = @.sku

Adamus

|||

Is this the trigger code? It doesn't seem right. For one, you are looking at rows in the base table and not just the rows affected by the DML operation in the trigger. And you don't need a cursor logic which hurts performance and creates more locking issues since the trigger is in a transaction. Also, the query for the cursor doesn't have any order by so you could process the same rows in different order from different transactions and end up deadlocked. Can you post a simple schema for the base table and the additional table that you need to maintain including the columns? This will help to suggest a simpler trigger code.

|||Using NOLOCK will not prevent all deadlocks. You have to first determine the cause of the deadlock and the resource in contention. With the trigger logic, it will in fact result in wrong results because you will be considering rows from transactions that can be potentially rolled back. It is easy to abuse NOLOCK hint without realizing the impact.|||

hi alex,

try removing that cursor inside the trigger replace it

with multiple update/delete from inserted and deleted tables

regards

|||

Thank to your help

there are trigger purpose and table structure

Alex

** purpose task
customer buys goods (parent) at shop
a parent goods may be two child goods or a set of child goods
and i need to update inventory balance at the realtime

** details task
table [itmhist] as transaction record installed trigger.
trigger use parent goods to find child goods at table [invset]
update the inventory balance of child goods at table [invbal]

/* trigger was installed at this table */
/* sku mean goods id */
CREATE TABLE [ITMHIST] (
[SHOP] [varchar] (7) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[TXDATE] [smalldatetime] NOT NULL ,
[REG] [smallint] NOT NULL ,
[TX] [smallint] NOT NULL ,
[SEQ] [smallint] NOT NULL ,
[SKU] [varchar] (9) ,
[QTY] [int] NULL ,
CONSTRAINT [PK_ITMHIST] PRIMARY KEY CLUSTERED
(
[SHOP],
[TXDATE],
[REG],
[TX],
[SEQ]
) ON [PRIMARY]
) ON [PRIMARY]
GO

/* cursor and while loop table
purpose - use parent goods to find the child goods
sku is parent goods
item is child goods
*/
CREATE TABLE [INVSET] (
[SKU] [varchar] (9) COLLATE Chinese_Taiwan_Stroke_CI_AS NOT NULL ,
[ITEM] [varchar] (9) COLLATE Chinese_Taiwan_Stroke_CI_AS NOT NULL ,
[QUANTITY] [int] NULL ,
CONSTRAINT [PK_INVSET] PRIMARY KEY CLUSTERED
(
[SKU],
[ITEM]
) ON [PRIMARY]
) ON [PRIMARY]
GO

/* update table
purpose - update realtime inventory balance
slsqtyyes was yesterday sold goods
slsqtynow was today sold goods
slsqtynxt was tommorrow sold goods
*/
CREATE TABLE [INVBAL] (
[SHOP] [varchar] (7) COLLATE Chinese_Taiwan_Stroke_CI_AS NOT NULL ,
[SKU] [varchar] (9) COLLATE Chinese_Taiwan_Stroke_CI_AS NOT NULL ,
[OPENDATE] [datetime] NULL ,
[SLSQTYYES] [numeric](10, 0) NULL CONSTRAINT [DF_INVBAL_SLSQTYYES] DEFAULT (0),
[SLSQTYNOW] [numeric](10, 0) NULL CONSTRAINT [DF_INVBAL_SLSQTYNOW] DEFAULT (0),
[SLSQTYNXT] [numeric](10, 0) NULL CONSTRAINT [DF_INVBAL_SLSQTY] DEFAULT (0),
CONSTRAINT [PK_INVBAL] PRIMARY KEY CLUSTERED
(
[SHOP],
[SKU]
) ON [PRIMARY]
) ON [PRIMARY]
GO


|||

Umachandar Jayachandran - MS wrote:

Using NOLOCK will not prevent all deadlocks. You have to first determine the cause of the deadlock and the resource in contention. With the trigger logic, it will in fact result in wrong results because you will be considering rows from transactions that can be potentially rolled back. It is easy to abuse NOLOCK hint without realizing the impact.

Well considering I focused on (NOLOCKS) with SELECT's only, I'm confused on how you incorporated transactions into this. Do you use transactions on SELECTs?

Also, the trigger logic is fired after the events. Protocol suggest rollbacks have already been completed prior to the trigger or exist inside the trigger. In either event, the results will be accurate.

It is easy to be lead astray on tangeants when you're uncertain of the desired resultset.

Adamus

|||

Umachandar Jayachandran - MS wrote:

Is this the trigger code? It doesn't seem right. For one, you are looking at rows in the base table and not just the rows affected by the DML operation in the trigger. And you don't need a cursor logic which hurts performance and creates more locking issues since the trigger is in a transaction.

Could you explain more on how a cursor causes locking issues any more than an alternative approach?

Umachandar Jayachandran - MS wrote:

Also, the query for the cursor doesn't have any order by so you could process the same rows in different order from different transactions and end up deadlocked.

Also, can you explain more on how ordering/sorting the records would cause records to be read twice in the cursor?

Umachandar Jayachandran - MS wrote:

Can you post a simple schema for the base table and the additional table that you need to maintain including the columns? This will help to suggest a simpler trigger code.

How much simpler could it be?

Adamus

|||

Please read the trigger topic in SQL Server Books Online to start with. Trigger are always in an implicit transaction so whatever code you write executes within a transaction. And also read about read uncommitted transaction isolation level in Books Online. Read uncommitted means you can look at currently executing transactions in the system (you are not isolated from changes happening in the system).

See below pseudo-code showing interleaved operations between 2 connections:

begin tran connection#1

insert into table values(1) connection#1

declare cursor ... select * from table (nolock) connection #2 inside trigger will get row above

fetch .... -- connection #2, now you have read row from connection #1

rollback connection #1

... some other logic in connection #2, now you are doing something with a row that doesn't exist!

>> Also, the trigger logic is fired after the events. Protocol suggest rollbacks have already been completed

>> prior to the trigger or exist inside the trigger. In either event, the results will be accurate

You need to read about how triggers work and what each transaction isolation level means (including NOLOCK hint). See topics below:

-- trigger related topics:

http://msdn2.microsoft.com/en-us/library/ms189799.aspx

http://msdn2.microsoft.com/en-us/library/ms178110.aspx

http://msdn2.microsoft.com/en-us/library/ms189261.aspx

-- isolation level related topics:

http://msdn2.microsoft.com/en-us/library/ms173763.aspx

http://msdn2.microsoft.com/en-us/library/ms173763.aspx

http://msdn2.microsoft.com/en-us/library/ms189122.aspx

http://msdn2.microsoft.com/en-us/library/ms190805.aspx

|||

>> Could you explain more on how a cursor causes locking issues any more than an alternative approach?

Depending on the type of cursor, the execution strategy is different. An insensitive cursor makes a copy of the rows in temporary table so it is not an atomic operation - the results are persisted upon OPEN cursor. Keyset cursor uses keys persisted in temporary table but every fetch incurs SELECT overhead. Dynamic cursor is susceptible to other changes happening in the system and depending on isolation level you may end up reading rows that are rolled back. See the topics in my other post to understand how isolation level works. If you use a SELECT statement then it is easy to understand the locking issues if you know the isolation level for starters.

>> Also, can you explain more on how ordering/sorting the records would cause records to be read twice in the

>> cursor?

I didn't say records. I said rows so there is a difference. And I didn't say that rows are read twice. I said that rows could be processed in different order leading to deadlock. The user's code had a SELECT against the base table so if two concurrent transactions fired the trigger both will be looking at the base table. And depending on the execution plan the order of the rows might differ (see how SELECT statement works in Books Online and the ordering guarantees). So connection #1 may process rows in different order than connection #2.

>> How much simpler could it be?

As I can see from your responses it has not really helped the user in any way. It is best to look at sample DDL and data for newsgroup problems to give the correct solution. It is easy to talk vaguely or point in multiple directions.

|||

Thanks for posting the sample schema. Some more explanation on the rules would have been helpful. Anyway, I created some sample trigger code based on what I could understand from your comments in the script above.

-- Insert sample inventory data set:

INSERT INTO [INVSET] ([SKU], [ITEM], [QUANTITY]) VALUES( 'p1', 'c1', 10 )
INSERT INTO [INVSET] ([SKU], [ITEM], [QUANTITY]) VALUES( 'p1', 'c2', 5 )
INSERT INTO [INVSET] ([SKU], [ITEM], [QUANTITY]) VALUES( 'p2', 'c2', 5 )
INSERT INTO [INVSET] ([SKU], [ITEM], [QUANTITY]) VALUES( 'p2', 'c3', 20 )
go

-- Trigger to maintain inventory balance upon insert:

create trigger insert_ITMHIST on ITMHIST
after insert
as
begin
set transaction isolation level serializable
-- Update existing inventory items first:
update [INVBAL]
set [SLSQTYNOW] = [SLSQTYNOW] + CASE WHEN i3.[TXDATE] <= [INVBAL].[OPENDATE] THEN i3.[QUANTITY] * i3.[QTY] ELSE 0 END
, [SLSQTYNXT] = [SLSQTYNXT] + CASE WHEN i3.[TXDATE] > [INVBAL].[OPENDATE] THEN i3.[QUANTITY] * i3.[QTY] ELSE 0 END
from (
select i.[SHOP], i.[TXDATE], i2.[ITEM], i.[QTY], i2.[QUANTITY]
from inserted as i
join [INVSET] as i2
on i2.[SKU] = i.[SKU]
) as i3
where i3.[SHOP] = [INVBAL].[SHOP] and i3.[ITEM] = [INVBAL].[SKU]

-- add new inventorty items next:
insert into [INVBAL] ([SHOP], [SKU], [OPENDATE], [SLSQTYNOW], [SLSQTYYES], [SLSQTYNXT])
select i.[SHOP], i2.[ITEM], i.[TXDATE], i.[QTY] * i2.[QUANTITY], 0, 0
from inserted as i
join [INVSET] as i2
on i2.[SKU] = i.[SKU]
where not exists(select * from [INVBAL] as i3
where i3.[SHOP] = i.[SHOP] and i3.[SKU] = i2.[ITEM])
end
go

-- view approach:

create view INVBAL_RT
as
select ih.[SHOP], i.[ITEM] as SKU, SUM( i.[QUANTITY] * ih.[QTY] ) as QTY
from dbo.[ITMHIST] as ih
join dbo.[INVSET] as i
on i.[SKU] = ih.[SKU]
group by ih.[SHOP], i.[ITEM]
go

begin tran

-- Try some test inserts:

insert into ITMHIST values('a', '20060814', 1, 1, 1, 'p1', 2)
select * from INVBAL

select * from INVBAL_RT

insert into ITMHIST values('a', '20060814', 1, 2, 1, 'p1', 2)
select * from INVBAL
select * from INVBAL_RT

insert into ITMHIST values('a', '20060815', 1, 1, 1, 'p2', 1)

select * from INVBAL
select * from INVBAL_RT

rollback
go

-- cleanup tables:

drop table INVSET, INVBAL, ITMHIST

drop view INVBAL_RT

go

The trigger code above should give you an idea of how to simplify your existing logic. I also used serializable isolation level inside trigger code. Alternatively, you can just create a view to show the real-time inventory data instead of persisting in the table. You could index the view for performance although it has some overhead in terms of maintainenence during DML operations on the base tables. But you could compare it with the trigger logic.

Btw, if you want to retain your existing trigger logic assuming everything works except for the deadlock you can use the link below to troubleshoot the deadlock issue. SQL Server 2005 has new trace flag that provides richer output for deadlock detection including the conflicting statements.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/trblsql/tr_servdatabse_5xrn.asp

|||

hi all,

I collect your suggestions and modify my program.
it seems ok, but i am not sure.
there is my final product. please give me some advise if you find out risk in my code.

my main modification is stroke out "local static" at cursor loop.
add "no lock" at each select, add serializable in trigger, "set nocount on" at the beginning and "set nocount off" at the end.

thank a lot
alex

-

alter TRIGGER tr_SKYTSP_INVBAL
ON dbo.ITMHIST
FOR INSERT
AS
SET NOCOUNT ON
set transaction isolation level serializable

DECLARE @.shop varchar(7), @.txdate smalldatetime, @.sku varchar(9),
@.setsku varchar(1), @.invsetitem varchar(9), @.invsetqty smallint,
@.opendate smalldatetime, @.itmtxqty smallint, @.balsku varchar(9), @.bizdate smalldatetime

SELECT @.shop = SHOP, @.sku = SKU, @.txdate = TXDATE, @.itmtxqty = qty From Inserted
SELECT @.setsku = setsku from INVMST (NOLOCK) where SKU = @.sku
select @.bizDate = CONVERT(char(10), BUSSINDATE,101) FROM chain.dbo.CNTRL (NOLOCK)

if (@.sku is not null)
begin
if (@.setsku = 1)
begin
declare setskuCursor cursor
for select item, quantity from invset (NOLOCK) where sku = @.sku
open setskuCursor
fetch next from setskuCursor into @.invsetitem, @.invsetqty
while @.@.fetch_status = 0
begin
set @.balsku = '000000'
select @.balsku = sku, @.opendate = opendate from invbal (NOLOCK) where sku = @.invsetitem
if (@.balsku <> '000000')
begin
if @.txdate <= @.opendate
update invbal set slsqtynow = slsqtynow + @.itmtxqty * @.invsetqty where sku = @.invsetitem
if @.txdate > @.opendate
update invbal set slsqtynxt = slsqtynxt + @.itmtxqty * @.invsetqty where sku = @.invsetitem
end
else
INSERT INTO INVBAL (SHOP, SKU, OPENDATE, SLSQTYNOW) VALUES (@.shop, @.invsetitem, @.bizdate, @.itmtxqty * @.invsetqty)
fetch next from setskuCursor into @.invsetitem, @.invsetqty
end
close setskuCursor
deallocate setskuCursor
end

else
begin
set @.balsku = '000000'
select @.balsku = sku, @.opendate = opendate from invbal (NOLOCK) where sku = @.sku
if (@.balsku <> '000000')
begin
if @.txdate <= @.opendate
update invbal set slsqtynow = slsqtynow + @.itmtxqty where sku = @.sku
if @.txdate > @.opendate
update invbal set slsqtynxt = slsqtynxt + @.itmtxqty where sku = @.sku
end
else
INSERT INTO INVBAL (SHOP, SKU, OPENDATE, SLSQTYNOW) VALUES (@.shop, @.sku, @.bizdate, @.itmtxqty)
end
end
SET NOCOUNT off
Go

|||

I am not sure why you added NOLOCK in your SELECT statements. As I pointed out multiple times in this thread, it will produce wrong results based on your concurrency and will lead to other problems. There are even query execution plans where you will get duplicates with NOLOCK i.e., you will end up reading the same row multiple times within the same query. Reading same row multiple times can happen when a split happens on the table and the row gets moved to a different location & the query ends up reading it again. This is perfectly fine for semantics of a dirty read which is what NOLOCK implies. So your real-time inventory balance will be incorrect. NOLOCK means no transactional consistency in the data that you read. If it is fine for you to have insufficient or wrong real-time inventory balance then you can use NOLOCK everywhere. Note that this may still not solve the deadlock issue because that could be due to parallelism in one of your queries for example. You may have to troubleshoot that next.

Your logic still doesn't take care of multiple rows inserted into the table. If that happens the behavior of trigger will be unpredictable i.e., you will not know which one of the inserted rows will be updated in the balance. Please take a look at the code that I posted. Try to modify and use that. Starting with the simple inventory balance update scenario of say inserting multiple SKUs will help understand the code & then you can incorporate more logic. It handles multiple rows being inserted/updated. It uses set-based operations and it is less resource intensive especially when executed within a trigger code which is in a transaction always.

|||

Umachandar Jayachandran - MS wrote:

Please read the trigger topic in SQL Server Books Online to start with. Trigger are always in an implicit transaction so whatever code you write executes within a transaction. And also read about read uncommitted transaction isolation level in Books Online. Read uncommitted means you can look at currently executing transactions in the system (you are not isolated from changes happening in the system).

See below pseudo-code showing interleaved operations between 2 connections:

begin tran connection#1

insert into table values(1) connection#1

declare cursor ... select * from table (nolock) connection #2 inside trigger will get row above

fetch .... -- connection #2, now you have read row from connection #1

rollback connection #1

... some other logic in connection #2, now you are doing something with a row that doesn't exist!

>> Also, the trigger logic is fired after the events. Protocol suggest rollbacks have already been completed

>> prior to the trigger or exist inside the trigger. In either event, the results will be accurate

You need to read about how triggers work and what each transaction isolation level means (including NOLOCK hint). See topics below:

-- trigger related topics:

http://msdn2.microsoft.com/en-us/library/ms189799.aspx

http://msdn2.microsoft.com/en-us/library/ms178110.aspx

http://msdn2.microsoft.com/en-us/library/ms189261.aspx

-- isolation level related topics:

http://msdn2.microsoft.com/en-us/library/ms173763.aspx

http://msdn2.microsoft.com/en-us/library/ms173763.aspx

http://msdn2.microsoft.com/en-us/library/ms189122.aspx

http://msdn2.microsoft.com/en-us/library/ms190805.aspx

Um "Instead of" triggers? Ever heard of them?|||

So how will instead of trigger solve this particular problem? How does it relate to your previous statement? Instead of trigger is also in a transaction though it fires in lieu of the DML action. Check for @.@.TRANCOUNT value inside instead of trigger code and see. You will have to anyway issue the same or similar set of DML actions against the base tables. Instead of triggers do not magically solve concurrency or locking issues. The main purpose of INSTEAD OF triggers or motivation behind adding it in the ANSI SQL standards was to allow DML operations on non-updateable views.

As I said before, you need to read about triggers (after and instead of) and how they work transactionally especially when different isolation levels are in effect. Isolation levels by themselves are a different beast and the topics I posted will illuminate you on those areas. Jim Gray's whitepaper on transactions is also a good start for this one.

Deadlock at trigger


a trigger need to insert or update record at the other table in high traffic environments
however, the deadlock happens; ie, a trigger running twice at the same time want to need to insert record at the table.

i trid to change isolation as SERIALIZABLE or REPEATABLE , but i cannot solve the problem. i guess the "while loop" affects the result because i try to cancel the loop and execute smoothly.

? How to solve the deadlock?
Thx

--
i used the following commands to change isolation level:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
begin transaction
commit transaction

--
the code are as follows:
declare setskuCursor cursor
local
static
for select item, quantity from invset where sku = @.sku
open setskuCursor
fetch next from setskuCursor into @.invsetitem, @.invsetqty
while @.@.fetch_status = 0
begin

select @.balsku = sku, @.opendate = opendate from invbal where sku = @.invsetitem
if (@.balsku is not null)
begin
if @.txdate <= @.opendate
update invbal set slsqtynow = slsqtynow + @.itmtxqty * @.invsetqty where sku = @.invsetitem
if @.txdate > @.opendate
update invbal set slsqtynxt = slsqtynxt + @.itmtxqty * @.invsetqty where sku = @.invsetitem
end
else
begin

INSERT INTO INVBAL (SHOP, SKU, OPENDATE, SLSQTYNOW) VALUES (@.shop, @.invsetitem, @.bizdate, @.itmtxqty * @.invsetqty)

end
fetch next from setskuCursor into @.invsetitem, @.invsetqty
end
close setskuCursor
deallocate setskuCursor
-

Use (NOLOCK) on all SELECT...

select item, quantity from invset (NOLOCK) where sku = @.sku

Adamus

|||

Is this the trigger code? It doesn't seem right. For one, you are looking at rows in the base table and not just the rows affected by the DML operation in the trigger. And you don't need a cursor logic which hurts performance and creates more locking issues since the trigger is in a transaction. Also, the query for the cursor doesn't have any order by so you could process the same rows in different order from different transactions and end up deadlocked. Can you post a simple schema for the base table and the additional table that you need to maintain including the columns? This will help to suggest a simpler trigger code.

|||Using NOLOCK will not prevent all deadlocks. You have to first determine the cause of the deadlock and the resource in contention. With the trigger logic, it will in fact result in wrong results because you will be considering rows from transactions that can be potentially rolled back. It is easy to abuse NOLOCK hint without realizing the impact.|||

hi alex,

try removing that cursor inside the trigger replace it

with multiple update/delete from inserted and deleted tables

regards

|||

Thank to your help

there are trigger purpose and table structure

Alex

** purpose task
customer buys goods (parent) at shop
a parent goods may be two child goods or a set of child goods
and i need to update inventory balance at the realtime

** details task
table [itmhist] as transaction record installed trigger.
trigger use parent goods to find child goods at table [invset]
update the inventory balance of child goods at table [invbal]

/* trigger was installed at this table */
/* sku mean goods id */
CREATE TABLE [ITMHIST] (
[SHOP] [varchar] (7) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[TXDATE] [smalldatetime] NOT NULL ,
[REG] [smallint] NOT NULL ,
[TX] [smallint] NOT NULL ,
[SEQ] [smallint] NOT NULL ,
[SKU] [varchar] (9) ,
[QTY] [int] NULL ,
CONSTRAINT [PK_ITMHIST] PRIMARY KEY CLUSTERED
(
[SHOP],
[TXDATE],
[REG],
[TX],
[SEQ]
) ON [PRIMARY]
) ON [PRIMARY]
GO

/* cursor and while loop table
purpose - use parent goods to find the child goods
sku is parent goods
item is child goods
*/
CREATE TABLE [INVSET] (
[SKU] [varchar] (9) COLLATE Chinese_Taiwan_Stroke_CI_AS NOT NULL ,
[ITEM] [varchar] (9) COLLATE Chinese_Taiwan_Stroke_CI_AS NOT NULL ,
[QUANTITY] [int] NULL ,
CONSTRAINT [PK_INVSET] PRIMARY KEY CLUSTERED
(
[SKU],
[ITEM]
) ON [PRIMARY]
) ON [PRIMARY]
GO

/* update table
purpose - update realtime inventory balance
slsqtyyes was yesterday sold goods
slsqtynow was today sold goods
slsqtynxt was tommorrow sold goods
*/
CREATE TABLE [INVBAL] (
[SHOP] [varchar] (7) COLLATE Chinese_Taiwan_Stroke_CI_AS NOT NULL ,
[SKU] [varchar] (9) COLLATE Chinese_Taiwan_Stroke_CI_AS NOT NULL ,
[OPENDATE] [datetime] NULL ,
[SLSQTYYES] [numeric](10, 0) NULL CONSTRAINT [DF_INVBAL_SLSQTYYES] DEFAULT (0),
[SLSQTYNOW] [numeric](10, 0) NULL CONSTRAINT [DF_INVBAL_SLSQTYNOW] DEFAULT (0),
[SLSQTYNXT] [numeric](10, 0) NULL CONSTRAINT [DF_INVBAL_SLSQTY] DEFAULT (0),
CONSTRAINT [PK_INVBAL] PRIMARY KEY CLUSTERED
(
[SHOP],
[SKU]
) ON [PRIMARY]
) ON [PRIMARY]
GO


|||

Umachandar Jayachandran - MS wrote:

Using NOLOCK will not prevent all deadlocks. You have to first determine the cause of the deadlock and the resource in contention. With the trigger logic, it will in fact result in wrong results because you will be considering rows from transactions that can be potentially rolled back. It is easy to abuse NOLOCK hint without realizing the impact.

Well considering I focused on (NOLOCKS) with SELECT's only, I'm confused on how you incorporated transactions into this. Do you use transactions on SELECTs?

Also, the trigger logic is fired after the events. Protocol suggest rollbacks have already been completed prior to the trigger or exist inside the trigger. In either event, the results will be accurate.

It is easy to be lead astray on tangeants when you're uncertain of the desired resultset.

Adamus

|||

Umachandar Jayachandran - MS wrote:

Is this the trigger code? It doesn't seem right. For one, you are looking at rows in the base table and not just the rows affected by the DML operation in the trigger. And you don't need a cursor logic which hurts performance and creates more locking issues since the trigger is in a transaction.

Could you explain more on how a cursor causes locking issues any more than an alternative approach?

Umachandar Jayachandran - MS wrote:

Also, the query for the cursor doesn't have any order by so you could process the same rows in different order from different transactions and end up deadlocked.

Also, can you explain more on how ordering/sorting the records would cause records to be read twice in the cursor?

Umachandar Jayachandran - MS wrote:

Can you post a simple schema for the base table and the additional table that you need to maintain including the columns? This will help to suggest a simpler trigger code.

How much simpler could it be?

Adamus

|||

Please read the trigger topic in SQL Server Books Online to start with. Trigger are always in an implicit transaction so whatever code you write executes within a transaction. And also read about read uncommitted transaction isolation level in Books Online. Read uncommitted means you can look at currently executing transactions in the system (you are not isolated from changes happening in the system).

See below pseudo-code showing interleaved operations between 2 connections:

begin tran connection#1

insert into table values(1) connection#1

declare cursor ... select * from table (nolock) connection #2 inside trigger will get row above

fetch .... -- connection #2, now you have read row from connection #1

rollback connection #1

... some other logic in connection #2, now you are doing something with a row that doesn't exist!

>> Also, the trigger logic is fired after the events. Protocol suggest rollbacks have already been completed

>> prior to the trigger or exist inside the trigger. In either event, the results will be accurate

You need to read about how triggers work and what each transaction isolation level means (including NOLOCK hint). See topics below:

-- trigger related topics:

http://msdn2.microsoft.com/en-us/library/ms189799.aspx

http://msdn2.microsoft.com/en-us/library/ms178110.aspx

http://msdn2.microsoft.com/en-us/library/ms189261.aspx

-- isolation level related topics:

http://msdn2.microsoft.com/en-us/library/ms173763.aspx

http://msdn2.microsoft.com/en-us/library/ms173763.aspx

http://msdn2.microsoft.com/en-us/library/ms189122.aspx

http://msdn2.microsoft.com/en-us/library/ms190805.aspx

|||

>> Could you explain more on how a cursor causes locking issues any more than an alternative approach?

Depending on the type of cursor, the execution strategy is different. An insensitive cursor makes a copy of the rows in temporary table so it is not an atomic operation - the results are persisted upon OPEN cursor. Keyset cursor uses keys persisted in temporary table but every fetch incurs SELECT overhead. Dynamic cursor is susceptible to other changes happening in the system and depending on isolation level you may end up reading rows that are rolled back. See the topics in my other post to understand how isolation level works. If you use a SELECT statement then it is easy to understand the locking issues if you know the isolation level for starters.

>> Also, can you explain more on how ordering/sorting the records would cause records to be read twice in the

>> cursor?

I didn't say records. I said rows so there is a difference. And I didn't say that rows are read twice. I said that rows could be processed in different order leading to deadlock. The user's code had a SELECT against the base table so if two concurrent transactions fired the trigger both will be looking at the base table. And depending on the execution plan the order of the rows might differ (see how SELECT statement works in Books Online and the ordering guarantees). So connection #1 may process rows in different order than connection #2.

>> How much simpler could it be?

As I can see from your responses it has not really helped the user in any way. It is best to look at sample DDL and data for newsgroup problems to give the correct solution. It is easy to talk vaguely or point in multiple directions.

|||

Thanks for posting the sample schema. Some more explanation on the rules would have been helpful. Anyway, I created some sample trigger code based on what I could understand from your comments in the script above.

-- Insert sample inventory data set:

INSERT INTO [INVSET] ([SKU], [ITEM], [QUANTITY]) VALUES( 'p1', 'c1', 10 )
INSERT INTO [INVSET] ([SKU], [ITEM], [QUANTITY]) VALUES( 'p1', 'c2', 5 )
INSERT INTO [INVSET] ([SKU], [ITEM], [QUANTITY]) VALUES( 'p2', 'c2', 5 )
INSERT INTO [INVSET] ([SKU], [ITEM], [QUANTITY]) VALUES( 'p2', 'c3', 20 )
go

-- Trigger to maintain inventory balance upon insert:

create trigger insert_ITMHIST on ITMHIST
after insert
as
begin
set transaction isolation level serializable
-- Update existing inventory items first:
update [INVBAL]
set [SLSQTYNOW] = [SLSQTYNOW] + CASE WHEN i3.[TXDATE] <= [INVBAL].[OPENDATE] THEN i3.[QUANTITY] * i3.[QTY] ELSE 0 END
, [SLSQTYNXT] = [SLSQTYNXT] + CASE WHEN i3.[TXDATE] > [INVBAL].[OPENDATE] THEN i3.[QUANTITY] * i3.[QTY] ELSE 0 END
from (
select i.[SHOP], i.[TXDATE], i2.[ITEM], i.[QTY], i2.[QUANTITY]
from inserted as i
join [INVSET] as i2
on i2.[SKU] = i.[SKU]
) as i3
where i3.[SHOP] = [INVBAL].[SHOP] and i3.[ITEM] = [INVBAL].[SKU]

-- add new inventorty items next:
insert into [INVBAL] ([SHOP], [SKU], [OPENDATE], [SLSQTYNOW], [SLSQTYYES], [SLSQTYNXT])
select i.[SHOP], i2.[ITEM], i.[TXDATE], i.[QTY] * i2.[QUANTITY], 0, 0
from inserted as i
join [INVSET] as i2
on i2.[SKU] = i.[SKU]
where not exists(select * from [INVBAL] as i3
where i3.[SHOP] = i.[SHOP] and i3.[SKU] = i2.[ITEM])
end
go

-- view approach:

create view INVBAL_RT
as
select ih.[SHOP], i.[ITEM] as SKU, SUM( i.[QUANTITY] * ih.[QTY] ) as QTY
from dbo.[ITMHIST] as ih
join dbo.[INVSET] as i
on i.[SKU] = ih.[SKU]
group by ih.[SHOP], i.[ITEM]
go

begin tran

-- Try some test inserts:

insert into ITMHIST values('a', '20060814', 1, 1, 1, 'p1', 2)
select * from INVBAL

select * from INVBAL_RT

insert into ITMHIST values('a', '20060814', 1, 2, 1, 'p1', 2)
select * from INVBAL
select * from INVBAL_RT

insert into ITMHIST values('a', '20060815', 1, 1, 1, 'p2', 1)

select * from INVBAL
select * from INVBAL_RT

rollback
go

-- cleanup tables:

drop table INVSET, INVBAL, ITMHIST

drop view INVBAL_RT

go

The trigger code above should give you an idea of how to simplify your existing logic. I also used serializable isolation level inside trigger code. Alternatively, you can just create a view to show the real-time inventory data instead of persisting in the table. You could index the view for performance although it has some overhead in terms of maintainenence during DML operations on the base tables. But you could compare it with the trigger logic.

Btw, if you want to retain your existing trigger logic assuming everything works except for the deadlock you can use the link below to troubleshoot the deadlock issue. SQL Server 2005 has new trace flag that provides richer output for deadlock detection including the conflicting statements.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/trblsql/tr_servdatabse_5xrn.asp

|||

hi all,

I collect your suggestions and modify my program.
it seems ok, but i am not sure.
there is my final product. please give me some advise if you find out risk in my code.

my main modification is stroke out "local static" at cursor loop.
add "no lock" at each select, add serializable in trigger, "set nocount on" at the beginning and "set nocount off" at the end.

thank a lot
alex

-

alter TRIGGER tr_SKYTSP_INVBAL
ON dbo.ITMHIST
FOR INSERT
AS
SET NOCOUNT ON
set transaction isolation level serializable

DECLARE @.shop varchar(7), @.txdate smalldatetime, @.sku varchar(9),
@.setsku varchar(1), @.invsetitem varchar(9), @.invsetqty smallint,
@.opendate smalldatetime, @.itmtxqty smallint, @.balsku varchar(9), @.bizdate smalldatetime

SELECT @.shop = SHOP, @.sku = SKU, @.txdate = TXDATE, @.itmtxqty = qty From Inserted
SELECT @.setsku = setsku from INVMST (NOLOCK) where SKU = @.sku
select @.bizDate = CONVERT(char(10), BUSSINDATE,101) FROM chain.dbo.CNTRL (NOLOCK)

if (@.sku is not null)
begin
if (@.setsku = 1)
begin
declare setskuCursor cursor
for select item, quantity from invset (NOLOCK) where sku = @.sku
open setskuCursor
fetch next from setskuCursor into @.invsetitem, @.invsetqty
while @.@.fetch_status = 0
begin
set @.balsku = '000000'
select @.balsku = sku, @.opendate = opendate from invbal (NOLOCK) where sku = @.invsetitem
if (@.balsku <> '000000')
begin
if @.txdate <= @.opendate
update invbal set slsqtynow = slsqtynow + @.itmtxqty * @.invsetqty where sku = @.invsetitem
if @.txdate > @.opendate
update invbal set slsqtynxt = slsqtynxt + @.itmtxqty * @.invsetqty where sku = @.invsetitem
end
else
INSERT INTO INVBAL (SHOP, SKU, OPENDATE, SLSQTYNOW) VALUES (@.shop, @.invsetitem, @.bizdate, @.itmtxqty * @.invsetqty)
fetch next from setskuCursor into @.invsetitem, @.invsetqty
end
close setskuCursor
deallocate setskuCursor
end

else
begin
set @.balsku = '000000'
select @.balsku = sku, @.opendate = opendate from invbal (NOLOCK) where sku = @.sku
if (@.balsku <> '000000')
begin
if @.txdate <= @.opendate
update invbal set slsqtynow = slsqtynow + @.itmtxqty where sku = @.sku
if @.txdate > @.opendate
update invbal set slsqtynxt = slsqtynxt + @.itmtxqty where sku = @.sku
end
else
INSERT INTO INVBAL (SHOP, SKU, OPENDATE, SLSQTYNOW) VALUES (@.shop, @.sku, @.bizdate, @.itmtxqty)
end
end
SET NOCOUNT off
Go

|||

I am not sure why you added NOLOCK in your SELECT statements. As I pointed out multiple times in this thread, it will produce wrong results based on your concurrency and will lead to other problems. There are even query execution plans where you will get duplicates with NOLOCK i.e., you will end up reading the same row multiple times within the same query. Reading same row multiple times can happen when a split happens on the table and the row gets moved to a different location & the query ends up reading it again. This is perfectly fine for semantics of a dirty read which is what NOLOCK implies. So your real-time inventory balance will be incorrect. NOLOCK means no transactional consistency in the data that you read. If it is fine for you to have insufficient or wrong real-time inventory balance then you can use NOLOCK everywhere. Note that this may still not solve the deadlock issue because that could be due to parallelism in one of your queries for example. You may have to troubleshoot that next.

Your logic still doesn't take care of multiple rows inserted into the table. If that happens the behavior of trigger will be unpredictable i.e., you will not know which one of the inserted rows will be updated in the balance. Please take a look at the code that I posted. Try to modify and use that. Starting with the simple inventory balance update scenario of say inserting multiple SKUs will help understand the code & then you can incorporate more logic. It handles multiple rows being inserted/updated. It uses set-based operations and it is less resource intensive especially when executed within a trigger code which is in a transaction always.

|||

Umachandar Jayachandran - MS wrote:

Please read the trigger topic in SQL Server Books Online to start with. Trigger are always in an implicit transaction so whatever code you write executes within a transaction. And also read about read uncommitted transaction isolation level in Books Online. Read uncommitted means you can look at currently executing transactions in the system (you are not isolated from changes happening in the system).

See below pseudo-code showing interleaved operations between 2 connections:

begin tran connection#1

insert into table values(1) connection#1

declare cursor ... select * from table (nolock) connection #2 inside trigger will get row above

fetch .... -- connection #2, now you have read row from connection #1

rollback connection #1

... some other logic in connection #2, now you are doing something with a row that doesn't exist!

>> Also, the trigger logic is fired after the events. Protocol suggest rollbacks have already been completed

>> prior to the trigger or exist inside the trigger. In either event, the results will be accurate

You need to read about how triggers work and what each transaction isolation level means (including NOLOCK hint). See topics below:

-- trigger related topics:

http://msdn2.microsoft.com/en-us/library/ms189799.aspx

http://msdn2.microsoft.com/en-us/library/ms178110.aspx

http://msdn2.microsoft.com/en-us/library/ms189261.aspx

-- isolation level related topics:

http://msdn2.microsoft.com/en-us/library/ms173763.aspx

http://msdn2.microsoft.com/en-us/library/ms173763.aspx

http://msdn2.microsoft.com/en-us/library/ms189122.aspx

http://msdn2.microsoft.com/en-us/library/ms190805.aspx

Um "Instead of" triggers? Ever heard of them?|||

So how will instead of trigger solve this particular problem? How does it relate to your previous statement? Instead of trigger is also in a transaction though it fires in lieu of the DML action. Check for @.@.TRANCOUNT value inside instead of trigger code and see. You will have to anyway issue the same or similar set of DML actions against the base tables. Instead of triggers do not magically solve concurrency or locking issues. The main purpose of INSTEAD OF triggers or motivation behind adding it in the ANSI SQL standards was to allow DML operations on non-updateable views.

As I said before, you need to read about triggers (after and instead of) and how they work transactionally especially when different isolation levels are in effect. Isolation levels by themselves are a different beast and the topics I posted will illuminate you on those areas. Jim Gray's whitepaper on transactions is also a good start for this one.