Re: Quick question re: locks and triggers
From: Louis Davidson (dr_dontspamme_sql_at_hotmail.com)
Date: 08/06/04
- Next message: Yaheya Quazi: "Bulk insert.."
- Previous message: Stanley: "Gettig the count of lowest level"
- In reply to: Steve: "Re: Quick question re: locks and triggers"
- Next in thread: Steve Cutting: "Re: Quick question re: locks and triggers"
- Reply: Steve Cutting: "Re: Quick question re: locks and triggers"
- Messages sorted by: [ date ] [ thread ]
Date: Fri, 6 Aug 2004 10:16:59 -0500
Ok, I know what your concern is because it drove me batty for a long while.
The problem is what is locked, and for how long. Consider this scenario:
TableX has insert trigger TableXInsertTrigger that includes the following
statement:
if (select sum(value) from TableX) > 10
begin
raiserror 50000 'No more than 10'
rollback tran
end
A row is inserted. This new row is created, but is exclusively locked.
TableXInsertTrigger fires
The statement above fires, doing a table scan and locking the entire table.
However since you are in READ COMMITTED mode, locks should not be held from
this select statement, as such they will be released as soon as they are
used. It might be that it does not take a table lock, but rather a row lock
per row, one at a time reading the value for the aggregation, and then
releasing it and taking another.
So you do not end up with an exclusive table lock, just an exclusive row
lock, with a transitory shared lock on the table.
Now, notice one thing. This trigger would prevent other users from
inserting a row into the TableX table, since it has a row lock, no other
user can take even a shared table lock. This is why you have to be really
careful when building triggers.
This is why we have to keep our transactions very very short when using
triggers and READ COMMITTED isolation level. The only (important to this
discussion) locks that held after they are used are EXCLUSIVE locks. So
lets say you had the following statements in the trigger instead of the
other:
if (select sum(value) from TableY) > 10
begin
raiserror 50000 'No more than 10'
rollback tran
end
Now, we are checking another table, and after we do the check we hold no
locks on that table. Any other user can change the values in TableY without
any knowledge that you need the value to be greater than 10, since you will
hold no locks. This same phenomena is true for FOREIGN KEY constraints.
The minimum timing and likelihood of this sort of thing happening make it
very very unlikely, which is why we use READ COMMITTED as our default. If
your system is life or death, then you will want to step up the isolation
level to SERIALIZABLE, or at least use holdlock hints on the critical
tables.
Concurrency is FUN!
-- ---------------------------------------------------------------------------- Louis Davidson (drsql@hotmail.com) Compass Technology Management Pro SQL Server 2000 Database Design http://www.apress.com/book/bookDisplay.html?bID=266 Note: Please reply to the newsgroups only unless you are interested in consulting services. All other replies will be ignored :) "Steve" <anonymous@discussions.microsoft.com> wrote in message news:125501c47b8a$223db830$a501280a@phx.gbl... > Thankyou all for your responses. > > Can I please just confirm the following then... > 1) I start a transaction at default readcommitted isolation > 2) I do an insert into myTable with no locking hints > 3) the newly inserted row is exclusively locked > 4) trigger starts it's work, holding the lock on that row. > > Now whilst the trigger is running, it is still possible > for another user to insert a new row into myTable. > Correct ?? > > I am thinking of the scenario whereby the insert trigger > queries myTable itself in order to determine if the new > row is acceptable. As such there must not be any new rows > added during that query or the trigger might end up > allowing an invalid row to be added. For instance if the > trigger was checking for duplicate names in myTable. > (could be done with a unique property on a column but just > an example). If 2 users both did an insert at almost the > same instant, the second insert must wait for the 1st to > finish in order to include the (possibly) newly inserted > row in it's own trigger query. > > I'm guessing that you would need to insert with a tablock > hint to achieve this ?? ie suspend any writes to myTable > until the insert completes. > > thanks again > Steve >
- Next message: Yaheya Quazi: "Bulk insert.."
- Previous message: Stanley: "Gettig the count of lowest level"
- In reply to: Steve: "Re: Quick question re: locks and triggers"
- Next in thread: Steve Cutting: "Re: Quick question re: locks and triggers"
- Reply: Steve Cutting: "Re: Quick question re: locks and triggers"
- Messages sorted by: [ date ] [ thread ]
Relevant Pages
|