Serializable transaction isolation levels avoids the problem of phantom reads by blocking any inserts to a table in a transaction which are conflicting with any select statements in other transactions. I am trying to understand it with an example, but it blocks insert even if when the filter in the select statement is not conflicting. I would appreciate any explanation on why it behaves in that way.
Table Script
CREATE TABLE [dbo].[dummy](
[firstname] [char](20) NULL,
[lastname] [char](20) NULL
) ON [PRIMARY]
GO
Session – 1
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
begin tran
select * from dummy where firstname = 'abc'
Session – 2
insert into dummy values('lmn', 'lmn') -- Why this blocks?
The first issue in your test scenario is that the table has no useful index on
firstname. The second is that the table is empty.From Key-Range Locking in BOL
There is no suitable index to take
RangeS-Slocks on so to guarantee serializable semantics SQL Server needs to lock the whole table.If you try adding a clustered index on the table on the first name column as below and repeat the experiment …
… you will find that you are still blocked!
Despite the fact that a suitable index now exists and the execution plan shows that it is seeked into to satisfy the query.
You can see why by running the following
Returns
SQL Server does not just take out a range lock on exactly the range you specify in your query.
For an equality predicate on a unique index if there is a matching key it will just take a regular lock rather than any type of range lock at all.
For a non unique seek predicate it takes out locks on all matching keys within the range plus the "next" one at the end of the range (or on
ffffffffffffto represent infinity if no "next" key exists). Even deleted "ghost" records can be used in this range key locking.As described here for an equality predicate on either a unique or non unique index
So with an empty table the
SELECTstill ends up locking the entire index. You would need to also have previously inserted a row betweenabcandlmnand then your insert would succeed.