sql server a simple query takes forever to run due to transaction isolation level

5.1k views Asked by At

I've come across a problem while learning transaction isolation levels in SQL server.

The problem is that after I run this code (and it finishes without errors):

set implicit_transactions off;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRAN T1;

SELECT (...)
WAITFOR DELAY '00:00:5' 
SELECT (...)
WAITFOR DELAY '00:00:3' 

COMMIT TRAN T1;

I want to run this query:

set implicit_transactions off;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
BEGIN TRANSACTION T2;

INSERT (...)
INSERT (...)

COMMIT TRANSACTION T2;

But it just says "Executing query", and does nothing. I think it's because the lock on the tables somehow continues after the first transaction has been finished. Can someone help? Of course the selects and the inserts refer to the same tables.

3

There are 3 answers

0
usr On BEST ANSWER

Either the first tran is still open (close the window to make sure it is not), or some other tran is open (exec sp_who2). You can't suppress X-locks taken by DML because SQL Server needs those locks during rollback.

0
J0e3gan On

@usr offers good possibilities.

A related specific possibility is that you selected only part of the first transaction to execute while tinkering - i.e. executed BEGIN TRAN T1 and never executed COMMIT TRAN T1. It happens - part of Murphy's Law I think. Try executing just COMMIT TRAN T1, then re-trying the second snippet.

The following worked just fine for me on repeated, complete executions in a single session:

set implicit_transactions off;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRAN T1;

SELECT * from tbl_A
WAITFOR DELAY '00:00:5' 
SELECT * from tbl_B
WAITFOR DELAY '00:00:3' 

COMMIT TRAN T1;


set implicit_transactions off;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
BEGIN TRANSACTION T2;

INSERT tbl_A (ModifiedDate) values (GETDATE())
INSERT tbl_B (ModifiedDate) values (GETDATE())
INSERT tbl_A (ModifiedDate) select top 1 ModifiedDate from tbl_A
INSERT tbl_B (ModifiedDate) select top 1 ModifiedDate from tbl_B

COMMIT TRANSACTION T2;
0
CRAFTY DBA On

1 - SET IMPLICT_TRANSACTIONS is usually OFF unless you SET ANSI_DEFAULTS to ON. Then it will be ON. Thus, you can remove this extra statement if it is not needed.

2 - I agree with Aaron. Read uncommitted (no lock) should be used with a SELECT statement. However, this can lead to invalid results. It is prone to missing data, reading data twice, or scan errors.

Read Committed Snap Shot Isolation (RCSI) is a better option at the expense of tempdb (version store space). This will allow your reports (readers) not to be blocked by transactions (writers).

3 - Setting, SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, will use the most amount of locks. Therefore, increase the chances of blocking .

Why use this low concurrency isolation level with two INSERT statements?

I can understand using this level to UPDATE multiple tables. For instance, a bank transaction. Debit one row and Credit another row. Two tables. No one has access to the records until the transaction is complete.

In short, I would use READ COMMITTED isolation level for the insert statements. More than likely, the data being inserted is different.

However, the whole picture is not here.

There is some type of blocking that is occurring. You need to find the root cause.

Here is a code snippet to look at locks and objects that are locked.

--
-- Locked object details
-- 

-- Old school technique
EXEC sp_lock
GO

-- Lock details
SELECT
    resource_type, resource_associated_entity_id,
    request_status, request_mode,request_session_id,
    resource_description 
    FROM sys.dm_tran_locks
    WHERE resource_database_id = DB_ID('AdventureWorks2012')
GO

-- Page/Key details
SELECT object_name(object_id) as object_nm, *
    FROM sys.partitions
    WHERE hobt_id = 72057594047037440
GO

-- Object details
SELECT object_name(1266103551)
GO

If you still need help, please identify the two blocking transactions and the locks. Please post this information.