Transaction Isolation Level and Distributed Transactions

  • I vaguely remember reading somewhere that all distributed transactions are executed at Serializable Isolation Level "under the covers."

    1. Is this true?

    2. What does "under the covers" mean in this case; i.e. will I not see the isolation level represented accurately in requests?

    Jared
    CE - Microsoft

  • Looks like you're right. The only reference that I could find is this page in Paul Randal's blog: http://www.sqlskills.com/blogs/paul/worrying-wait-type/

    -- Gianluca Sartori

  • I performed some tests and it looks like it's not completely true (as far as I can tell):

    -- SETUP:

    -- 1. Create a linked server

    -- 2. Execute this at both servers:

    --SELECT *

    --INTO tempdb.dbo.spt_values

    --FROM master.dbo.spt_values

    -- TEST:

    SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

    SET XACT_ABORT ON;

    BEGIN TRAN

    -- Transaction isolation level before the transaction

    -- is promoted to distributed transaction

    SELECT transaction_isolation_level

    FROM sys.dm_exec_sessions

    WHERE session_id = @@spid

    UPDATE v

    SET name = 'rpc'

    FROM tempdb.dbo.spt_values AS v

    WHERE name = 'rpc'

    UPDATE v

    SET name = 'rpc'

    FROM [SQLCLP01\SQL2012].tempdb.dbo.spt_values AS v

    WHERE name = 'rpc'

    -- Transaction isolation level after the transaction

    -- is promoted to distributed transaction

    SELECT transaction_isolation_level

    FROM sys.dm_exec_sessions

    WHERE session_id = @@spid

    -- DON'T COMMIT OR ROLLBACK

    -- Connect to the server referenced in the linked server setup

    -- Run this:

    SELECT es.transaction_isolation_level

    FROM sys.dm_tran_active_transactions AS at

    INNER JOIN sys.dm_tran_session_transactions AS st

    ON at.transaction_id = st.transaction_id

    INNER JOIN sys.dm_exec_sessions AS es

    ON st.session_id = es.session_id

    WHERE transaction_type = 4

    In all cases, the transaction isolation level for the session is always 2 (READ COMMITTED).

    I have no idea what Paul meant with that statement.

    -- Gianluca Sartori

  • So, I just asked Paul at that same post you provided. He basically said that you won't see it, it just is serializable... Very interesting...

    Jared
    CE - Microsoft

  • Very interesting. What worries me is that I could find no documentation about it, just a tiny statement in Paul's post. Such an important information deserves better advertising IMHO

    -- Gianluca Sartori

  • I set up a test, and I can't even get Serializable to work right:

    Connection 1 on serverA:

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

    BEGIN TRAN

    SELECT * FROM serverB.database.schema.table WHERE idCol = 1;

    Returns 1 row

    Connection 2 on serverB:

    USE database

    UPDATE schema.table

    SET col2 = 1 WHERE idCol = 1

    (1 row(s) affected)

    When I change BEGIN TRAN to BEGIN DISTRIBUTED TRANSACTION, same thing... no blocking or waiting.

    Jared
    CE - Microsoft

  • SQLKnowItAll (3/10/2015)


    I set up a test, and I can't even get Serializable to work right:

    Connection 1 on serverA:

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

    BEGIN TRAN

    SELECT * FROM serverB.database.schema.table WHERE idCol = 1;

    Returns 1 row

    Connection 2 on serverB:

    USE database

    UPDATE schema.table

    SET col2 = 1 WHERE idCol = 1

    (1 row(s) affected)

    When I change BEGIN TRAN to BEGIN DISTRIBUTED TRANSACTION, same thing... no blocking or waiting.

    Change in code to get Serializable to work. Then I tested Distributed transaction and it did not:

    Connection 1 on serverA:

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

    BEGIN TRAN

    SELECT * FROM serverB.database.schema.table WHERE col2 = 1;

    Returns 1 row

    Connection 2 on serverB:

    USE database

    UPDATE schema.table

    SET col2 = 2 WHERE col2 = 1

    blocked! This is what we expected!

    Connection 1 on serverA:

    SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

    BEGIN DISTRIBUTED TRAN

    SELECT * FROM serverB.database.schema.table WHERE col2 = 1;

    Returns 1 row

    Connection 2 on serverB:

    USE database

    UPDATE schema.table

    SET col2 = 2 WHERE col2 = 1

    (1 row(s) affected) Hmm... If this was serializable, it should be blocked. Right?

    Jared
    CE - Microsoft

  • Exactly. Maybe we should ask Paul Randal to chime in. Let me ping him and see if he can drop by.

    -- Gianluca Sartori

  • So, I asked a few friends and turns out that if you don't set the transaction isolation level explicitly, it takes the default, which is read committed as far as the transaction is local and then escalates to serializable as soon as the transaction becomes distributed.

    I don't have a SQL instance to try now, but that's how it should work.

    Apparently, it depends on the DTC, which defaults to serializable.

    More info here: http://stackoverflow.com/questions/11292763/why-is-system-transactions-transactionscope-default-isolationlevel-serializable

    -- Gianluca Sartori

  • spaghettidba (3/10/2015)


    So, I asked a few friends and turns out that if you don't set the transaction isolation level explicitly, it takes the default, which is read committed as far as the transaction is local and then escalates to serializable as soon as the transaction becomes distributed.

    I don't have a SQL instance to try now, but that's how it should work.

    Apparently, it depends on the DTC, which defaults to serializable.

    More info here: http://stackoverflow.com/questions/11292763/why-is-system-transactions-transactionscope-default-isolationlevel-serializable

    Hmm... Even with not setting the level explicitly or defining the transaction as distributed, when I go the other server I can still update. I'll kepe playing to see if I can recreate this, but so far I am at a loss...

    Jared
    CE - Microsoft

Viewing 10 posts - 1 through 9 (of 9 total)

You must be logged in to reply to this topic. Login to reply