<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://sqlblog.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Snapshot isolation: A threat for integrity? (Part 4)</title><link>http://sqlblog.com/blogs/hugo_kornelis/archive/2006/09/15/Snapshot-and-integrity-part-4.aspx</link><description>In the previous parts of this series, I have shown how SQL Server prevents violations of foreign key constraints by silently disabling snapshot isolation . I have also demonstrated how you can use the same technique inside your trigger code , to keep</description><dc:language>en</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61129.1)</generator><item><title>re: Snapshot isolation: A threat for integrity? (Part 4)</title><link>http://sqlblog.com/blogs/hugo_kornelis/archive/2006/09/15/Snapshot-and-integrity-part-4.aspx#231</link><pubDate>Wed, 20 Sep 2006 18:45:14 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:231</guid><dc:creator>Alex Kuznetsov</dc:creator><description>Hi Hugo,&lt;br&gt;&lt;br&gt;Another way would be to create an indexed view as follows:&lt;br&gt;&lt;br&gt;CREATE VIEW dbo.CustomerTypeAOrders WITH SCHEMABINDING&lt;br&gt;AS&lt;br&gt;SELECT c.CustID, o.OrderId&lt;br&gt;FROM dbo.Orders o JOIN dbo.Customers c ON c.CustID = o.CustID&lt;br&gt;WHERE o.OrderType = 'A'&lt;br&gt;go&lt;br&gt;CREATE UNIQUE CLUSTERED INDEX UCI_CustomerTypeAOrders ON dbo.CustomerTypeAOrders(CustID, OrderId)&lt;br&gt;go&lt;br&gt;&lt;br&gt;Modifications will serialize because they will acquire update locks on dbo.CustomerTypeAOrders. Makes sense?&lt;br&gt;</description></item><item><title>re: Snapshot isolation: A threat for integrity? (Part 4)</title><link>http://sqlblog.com/blogs/hugo_kornelis/archive/2006/09/15/Snapshot-and-integrity-part-4.aspx#236</link><pubDate>Thu, 21 Sep 2006 16:42:34 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:236</guid><dc:creator>Hugo Kornelis</dc:creator><description>Hi Alex,&lt;br&gt;&lt;br&gt;Thanks for your thoughts.&lt;br&gt;&lt;br&gt;I don't see how this indexed view would prevent me from entering type 'A' orders for a non-existing customer. I've tried it, and I could execute&lt;br&gt;&lt;br&gt;INSERT INTO Orders (OrderID, OrderType, CustID)&lt;br&gt;VALUES ('O2', 'A', 3)&lt;br&gt;&lt;br&gt;just fine. Am I missing something?</description></item><item><title>re: Snapshot isolation: A threat for integrity? (Part 4)</title><link>http://sqlblog.com/blogs/hugo_kornelis/archive/2006/09/15/Snapshot-and-integrity-part-4.aspx#254</link><pubDate>Tue, 26 Sep 2006 17:30:17 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:254</guid><dc:creator>Alex Kuznetsov</dc:creator><description>Hi Hugo,&lt;br&gt;&lt;br&gt;Sorry for my incomplete explanations. Here is a complete repro script:&lt;br&gt;&lt;br&gt;CREATE TABLE Customers&lt;br&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;(CustID int NOT NULL PRIMARY KEY,&lt;br&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; CustName varchar(40) NOT NULL&lt;br&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;);&lt;br&gt;CREATE TABLE Orders&lt;br&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;(OrderID char(7) NOT NULL PRIMARY KEY,&lt;br&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; OrderType char(1) NOT NULL CHECK (OrderType IN ('A', 'B')),&lt;br&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; CustID int NOT NULL&lt;br&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;);&lt;br&gt;INSERT INTO Customers (CustID, CustName)&lt;br&gt;VALUES (1, 'First test customer');&lt;br&gt;INSERT INTO Customers (CustID, CustName)&lt;br&gt;VALUES (2, 'Second test customer');&lt;br&gt;go&lt;br&gt;&lt;br&gt;CREATE VIEW dbo.CustomerTypeAOrders WITH SCHEMABINDING &lt;br&gt;AS &lt;br&gt;SELECT c.CustID, o.OrderId &lt;br&gt;FROM dbo.Orders o JOIN dbo.Customers c ON c.CustID = o.CustID &lt;br&gt;WHERE o.OrderType = 'A' &lt;br&gt;go &lt;br&gt;CREATE UNIQUE CLUSTERED INDEX UCI_CustomerTypeAOrders ON dbo.CustomerTypeAOrders(CustID, OrderId) &lt;br&gt;go &lt;br&gt;&lt;br&gt;CREATE FUNCTION dbo.CustExists (@CustID int)&lt;br&gt;RETURNS char(1)&lt;br&gt;AS&lt;br&gt;BEGIN&lt;br&gt; &amp;nbsp;DECLARE @retval char(1)&lt;br&gt; &amp;nbsp;IF EXISTS (SELECT *&lt;br&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; FROM &amp;nbsp; dbo.Customers&lt;br&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; WHERE &amp;nbsp;CustID = @CustID)&lt;br&gt; &amp;nbsp; &amp;nbsp; SET @retval = 'Y'&lt;br&gt; &amp;nbsp;ELSE&lt;br&gt; &amp;nbsp; &amp;nbsp; SET @retval = 'N'&lt;br&gt; &amp;nbsp;RETURN @retval&lt;br&gt;END;&lt;br&gt;go&lt;br&gt;ALTER TABLE dbo.Orders&lt;br&gt;ADD CONSTRAINT TypeAMustExist&lt;br&gt; &amp;nbsp; &amp;nbsp;CHECK (OrderType &amp;lt;&amp;gt; 'A' OR&lt;br&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; dbo.CustExists(CustID) = 'Y');&lt;br&gt;go&lt;br&gt;&lt;br&gt;-------------------- in the first tab run this&lt;br&gt;&lt;br&gt;SET TRANSACTION ISOLATION LEVEL SNAPSHOT;&lt;br&gt;BEGIN TRANSACTION;&lt;br&gt;&lt;br&gt;-- 1. Check to see that the customer has no orders&lt;br&gt;&lt;br&gt;SELECT *&lt;br&gt;&lt;br&gt;FROM &amp;nbsp; Orders&lt;br&gt;&lt;br&gt;WHERE &amp;nbsp;CustID = 1;&lt;br&gt;&lt;br&gt;-- Remove the customer&lt;br&gt;&lt;br&gt;DELETE Customers&lt;br&gt;&lt;br&gt;WHERE &amp;nbsp;CustID = 1;&lt;br&gt;--- but do not commit yet&lt;br&gt;&lt;br&gt;---- 2. in the second tab run this:&lt;br&gt;SET TRANSACTION ISOLATION LEVEL SNAPSHOT;&lt;br&gt;&lt;br&gt;BEGIN TRANSACTION;&lt;br&gt;&lt;br&gt;-- Check to see that the customer exists&lt;br&gt;&lt;br&gt;SELECT *&lt;br&gt;&lt;br&gt;FROM &amp;nbsp; Customers&lt;br&gt;&lt;br&gt;WHERE &amp;nbsp;CustID = 1;&lt;br&gt;&lt;br&gt;-- Insert an order for the customer&lt;br&gt;&lt;br&gt;INSERT INTO Orders (OrderID, OrderType, CustID)&lt;br&gt;&lt;br&gt;VALUES ('Order01', 'A', 1);&lt;br&gt;-- statement hangs&lt;br&gt;&lt;br&gt;--- 3. open up an Activity window and note that the command is suspended&lt;br&gt;&lt;br&gt;--- 4. go to first window and commit&lt;br&gt;-- note that the second window displays an error right away:&lt;br&gt;&lt;br&gt;(1 row(s) affected)&lt;br&gt;Msg 3960, Level 16, State 2, Line 15&lt;br&gt;Snapshot isolation transaction aborted due to update conflict. You cannot use snapshot isolation to access table 'dbo.Customers' directly or indirectly in database 'Sandbox' to update, delete, or insert the row that has been modified or deleted by another transaction. Retry the transaction or change the isolation level for the update/delete statement.&lt;br&gt;&lt;br&gt;---- 5. Run SELECT @@SPID In both windows and make sure they match what you saw in Activity Monitor&lt;br&gt;--- 6. restore the data:&lt;br&gt;INSERT INTO Customers (CustID, CustName)&lt;br&gt;VALUES (1, 'First test customer');&lt;br&gt;--- 7. and drop the view&lt;br&gt;DROP VIEW dbo.CustomerTypeAOrders&lt;br&gt;&lt;br&gt;--- now repeat steps 1 and 2 - this time you can add an orphan all right&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;</description></item><item><title>re: Snapshot isolation: A threat for integrity? (Part 4)</title><link>http://sqlblog.com/blogs/hugo_kornelis/archive/2006/09/15/Snapshot-and-integrity-part-4.aspx#17728</link><pubDate>Wed, 14 Oct 2009 04:12:52 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:17728</guid><dc:creator>Fabricio</dc:creator><description>&lt;p&gt;Hugo, has snapshot got any better in SQLServer 2008 ? Since I never used it on production (when I used, was with Firebird - which record versioning implementatio came from Interbase, which first version was on mid-80s), I never though MS has screwed so much....&lt;/p&gt;
&lt;p&gt;Sorry for writing on so old topic...&lt;/p&gt;
</description></item><item><title>re: Snapshot isolation: A threat for integrity? (Part 4)</title><link>http://sqlblog.com/blogs/hugo_kornelis/archive/2006/09/15/Snapshot-and-integrity-part-4.aspx#18224</link><pubDate>Sun, 25 Oct 2009 14:17:18 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:18224</guid><dc:creator>Hugo Kornelis</dc:creator><description>&lt;p&gt;Hi Fabricio,&lt;/p&gt;
&lt;p&gt;As far as I know, there have been no changes to snapshot in SQL Server 2008.&lt;/p&gt;
&lt;p&gt;However, I don't consider snapshot isolation to be bad, as I don't think there are better alternatives. The only way to preserve data integrity is to check modifications against existing (other) data. If you choose to use old, possibly stale, data for this check, you run the risk of ruining integrity. And if you choose to use current data, you have no choice but to wait until pending other changes to that data have been either committed or rolled back, in other words, until locks are released. Since integrity should be the first priority, I think Microsoft made the right choice. My only problem is that the phrase &amp;quot;readers don't block writers&amp;quot; is too simplistic.&lt;/p&gt;
&lt;p&gt;With custom-built integrity checks (triggers, CHECK constraints that call user-defined functions, etc), you get more control and more repsonsibility. You can override a snapshot setting by using SET TRANSACTION ISOLATION LEVEL or query hints to make sure that snapshot isolation, if in effect, will be bypassed for the check. Or you can choose to take the risk of checking against stale data. Your choice, and the consequences are yours as well.&lt;/p&gt;
&lt;p&gt;Thanks for your comment!&lt;/p&gt;
</description></item></channel></rss>