Search code examples
sqlsql-serversql-server-2005sql-server-2005-express

Transaction isolation and reading from multiple tables on SQL Server Express and SQL Server 2005


I have a database with a main table (lets call it Owner) and several sub tables with holdings (like Cars, Books etc).

For example:

  • Owner has columns: owner_id, name
  • Cars has columns: owner_id (foreign key), brand
  • Books has columns: owner_id (foreign key), title, author

My program should calculate statistics like How many BMW owners also owns a Harry Potter book using various third party libraries. I want to read all rows from all tables at the same time and then do the analysis in non-sql code.

I want to read all tables using separate Select * From X statements. I cannot use one big join since it would return too many rows ((owners * cars * books) instead of (owners + cars + books)). A Union doesn't cut it either since the tables contain different columns of different types.

I have set

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

but I'm having some issues anyway.

If I stress the database by running two threads, one randomly inserting or deleting and the other reading I sometimes get inconsistent results, like Cars have been deleted between reading Owners and reading the Cars table.

I have a few questions:

  1. What's the proper way of preventing modification when reading from multiple tables one by one? No table must be modified until all have been read.

    I'm using SQL Server 2005 (on network) and SQL Server 2005 Express (local). Can I explicitly get locks on multiple tables at the same time?

  2. If I run against my local SQL Server Express database, I can't make it work no matter what I do. If I run against my networked SQL server 2005 database, I can make it work (with some effort). Does SQL Server Express support transaction isolation level SERIALIZABLE? I believe it should. The differences could be due to a slow network connection but I don't know.

    On my local db, I can not prevent modification in between reads. That is, one thread is randomly deleting a random owner (first cars, then books, then owner) or inserting a new owner (insert owner, insert 2 cars, insert 2 books). Another thread is reading using:

    Begin Tran
    Select owner_id From Owner
    Select owner_id, brand From Cars
    Select owner_id, title, author From Books
    Commit Tran
    

    No matter what I do, sometimes I get an owner with zero cars or zero books. This should never happen since all inserts and deletes are in a single transaction. I seems like the express server doesn't lock Owner, Cars and Books statements at the same time.

    On the networked SQL Server 2005, it works fine but it could be because of a slow connection and thus lower probability of simultaneous execution.

  3. On my local db, I am starting every transaction with a dummy Select from all tables to prevent deadlocking. I don't understand why this prevents deadlocking but not modification of the tables. This is not necessary on the networked SQL Server 2005.

At the moment, I can't tell if I've misunderstood something about transaction isolation or if it's an issue with differences between SQL Server Express and SQL Server 2005. Any help or insights would be greatly appreciated.


Solution

  • Your choice of loading all data in one go means very few options:

    • Use sp_getapplock to serialise access through the relevant code
    • Use TABLOCKX, HOLDLOCK on the reads in a transaction

    You have issues because SET TRANSACTION ISOLATION LEVEL SERIALIZABLE only affects isolation of the locks: you need to control duration (HOLDLOCK) and granularity + mode (TABLOCKX)