I’ve run into an issue that I need clearer heads to think through. Occasionally this stored procedure (and many others similar to it):
CREATE PROC [dbo].[add_address1]
@recno int OUTPUT,
@clientID int,
@street varchar (23),
@city varchar (21),
@state varchar (2),
@zip varchar (9)
AS
declare @s int;
select @s = updated from is_clientindex where clientid = @clientID
insert into is_address1
(original_rec, clientID, street,city,state,zip)
values (@s + 1, @clientID, @street,@city,@state,@zip);
set @recno = @@IDENTITY;
Will attempt to insert null into original_rec, a column that doesn’t allow nulls. The table is_clientindex is a very busy table with lots of reads going on. Inserting or updating is rare.
I think what’s happening is that is_clientindex is locked, or in some other way unavailable. This causes the select to fail, eventually leading to the insert failing.
Does it sound like I’m on the right track?
Is there anything I should do to is_clientindex to help this locking issue? The table/database would have been created using the SQL Server 2005 defaults for locking.
Is there anything I should do to this stored procedure?
Unfortunately, I do need to check that updated flag in is_clientindex when inserting into this table. There’s no way around that.
Edits:
-
@ClientID is valid (we know this through debugging), and the is_clientindex table is foreign-keyed to everything else in the system so we know it didn’t vanish.
-
This only happens under heavy load with multiple users.
-
The Activity Monitor shows lots of PAGE locks, but I don’t know on what because the Object ID doesn’t correspond to anything in the sys.all_objects table.
By default SQL Server ignores errors inside T-SQL blocks and just tries to go on. So it all depends on how you use transactions:
If you manage transaction by yourself in T-SQL, you need to detect errors there and do a rollback.
If transaction is managed by calling application (either explicitly or by automatic transaction per statement) then, after error is reported to the application, transaction can be rolled back there.
In SQL Server 2005 or newer use TRY…CATCH block around procedure body to handle the lock timeout error.
In SQL Server 2000 you should do
or something similar after each statement that could fail. This also works in newer versions but is much more work for errors like lock timeout.
Setting LOCK_TIMEOUT will not help. If SQL Server detects an actual deadlock (as opposed to long wait on lock) it will raise an error anyway.
It is still more likely to be a logic error – @s is null after query.
You can add check and RAISERROR yourself if it happens.
Just to be sure.
It’s like assert() in normal programming language.