91

How long should it take to run

ALTER DATABASE [MySite] SET READ_COMMITTED_SNAPSHOT ON

I just ran it and it's taken 10 minutes.

How can I check if it is applied?

Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689
  • 1
    oops. wasn't enabled this whole time!! (seriously!) that explains the deadlocks. see my answer below for full findings and a better script to run – Simon_Weaver Dec 05 '12 at 20:37
  • 2
    The action itself completes nearly instantly. The reason it won't return is because it's waiting for other users to get out of the database. It's not like it's busy thinking, churning away, consuming resources; it's waiting for everyone to leave the room so it change flip the switch. – Ian Boyd Jul 29 '19 at 14:30
  • in case you have open connections and it takes too long you could force all open connection to rollback and apply the change. Be carefull with the potential impacts: ALTER DATABASE yourdb SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE – Daniel Belém Duarte Jun 08 '21 at 09:41

10 Answers10

76

You can check the status of the READ_COMMITTED_SNAPSHOT setting using the sys.databases view. Check the value of the is_read_committed_snapshot_on column. Already asked and answered.

As for the duration, Books Online states that there can't be any other connections to the database when this takes place, but it doesn't require single-user mode. So you may be blocked by other active connections. Run sp_who (or sp_who2) to see what else is connected to that database.

Community
  • 1
  • 1
Rick
  • 4,575
  • 1
  • 26
  • 20
  • thanks. its taken 40 minutes so far and is showing 0. its a 740mb database. fingers crossed i didnt break it – Simon_Weaver Oct 24 '08 at 03:16
  • 3
    Try to open another query window against that databse. If you can, then I expect your statement hasn't started running yet. – Rick Oct 24 '08 at 03:30
  • 3
    Yup. It should just take a few seconds on most databases. If it's taking longer it's waiting behind another (even non-active) connection to terminate before it can make the change. So you may need to find and KILL any spids currently connected (after evaluating what they're doing). THEN it should go quickly. – Michael K. Campbell Sep 09 '11 at 17:09
  • 20
    I recommend using the NO_WAIT option to fail immedately, if there are other open connections. E.g. 'ALTER DATABASE generic SET READ_COMMITTED_SNAPSHOT ON WITH NO_WAIT' – StefanR Sep 20 '12 at 13:37
  • 1
    If you can't find and kill the other connected SPIDs (or just don't care) you can always just restart the SQL Server instance. – David Murdoch Oct 10 '13 at 16:23
  • I was being blocked by **`spid11`**, which in my case is the server's **`CHECKPOINT`** process. Running `sp_who` showed my block while a checkpoint completes. – Ian Boyd Feb 14 '14 at 23:01
61

Try this:

ALTER DATABASE generic SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE
Hosam Aly
  • 41,555
  • 36
  • 141
  • 182
  • 2
    So what is the use of "WITH ROLLBACK IMMEDIATE" ? does that means it would automatically roll back when the query failed ? – Senior Systems Engineer Jun 12 '12 at 00:15
  • 7
    No, "WITH ROLLBACK IMMEDIATE" means that it will immediately rollback any open transactions before starting the ALTER DATABASE statement. I'd advise against this unless you've already checked what transactions are open and whether they can be safely rolled back. – Rick Jul 12 '12 at 12:35
  • Amazing, also reports progress of closing connections. You saved our bacon! – Tyeth Apr 26 '19 at 10:05
35

OK (I am the original questioner) so it turns out this whole time I didn't even have the darn thing enabled.

Here's the ultimate code to run to enable snapshot mode and make sure it is enabled.

SELECT is_read_committed_snapshot_on, snapshot_isolation_state_desc,snapshot_isolation_state FROM sys.databases WHERE name='shipperdb'

ALTER DATABASE shipperdb SET allow_snapshot_isolation ON
ALTER DATABASE shipperdb SET SINGLE_USER WITH ROLLBACK IMMEDIATE
ALTER DATABASE shipperdb SET read_committed_snapshot ON
ALTER DATABASE shipperdb SET MULTI_USER

SELECT is_read_committed_snapshot_on, snapshot_isolation_state_desc,snapshot_isolation_state FROM sys.databases WHERE name='shipperdb'

This works even with connections active (presumably you're fine with them getting kicked out).

You can see the before and after state and this should run almost immediately.


IMPORTANT:

The option READ_COMMITTED_SNAPSHOT above corresponds to IsolationLevel.ReadCommitted in .NET
The option ALLOW_SNAPSHOT_ISOLATION above corresponds to IsolationLevel.Snapshot in .NET

Great article about different versioning


.NET Tips:

Looks like Isolationlevel.ReadCommitted is allowed in code even if not enabled by the database. No warning is thrown. So do yourself a favor and be sure it is turned on before you assume it is for 3 years like I did!!!

If you're using C# you probably want the ReadCommitted IsolationLevel and not Snapshot - unless you are doing writes in this transaction.

READ COMMITTED SNAPSHOT does optimistic reads and pessimistic writes. In contrast, SNAPSHOT does optimistic reads and optimistic writes. (from here)

bool snapshotEnabled = true;

using (var t = new TransactionScope(TransactionScopeOption.Required,
               new TransactionOptions
{
     IsolationLevel = IsolationLevel.ReadCommitted
}))
{
     using (var shipDB = new ShipperDBDataContext())
     {

     }
}

In additional you may get an error about being 'unable to promote' a transaction. Search for 'promotion' in Introducing System.Transactions in the .NET Framework 2.0.

Unless you're doing something special like connecting to an external database (or second database) then something as simple as creating a new DataContext can cause this. I had a cache that 'spun up' its own datacontext at initialization and this was trying to escalate the transaction to a full distributed one.

The solution was simple :

        using (var tran = new TransactionScope(TransactionScopeOption.Suppress))
        {
            using (var shipDB = new ShipperDBDataContext())
            { 
                 // initialize cache
            }
        }

See also Deadlocked article by @CodingHorror

Community
  • 1
  • 1
Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689
  • 4
    I wanted to mention, since i wasn't sure: You **can** turn on `READ_COMMITTED_SNAPSHOT` independently of `ALLOW_SNAPSHOT_ISOLATION`. You can have `ALLOW_SNAPSHOT_ISOLATION` **off** and still benefit from `READ_COMMITTED_SNAPSHOT` being **on**. Tested: Microsoft SQL Server 2012 - 11.0.2100.60 – Ian Boyd Nov 17 '14 at 21:37
  • 4
    This option changes the way that READ COMMITTED is implemented. With the option off, SQL Server will use locks to control access. This is why your .NET code didn't generate a warning - you were still getting the behaviour, just done in a different (and more likely to deadlock) way. – Richard Oct 24 '16 at 15:13
  • This does not answer the original question, though written by the OP. It implements an alternative. – Mike M Nov 20 '19 at 22:54
9

Try this code:

if(charindex('Microsoft SQL Server 2005',@@version) > 0)
begin
    declare @sql varchar(8000)
    select @sql = '
    ALTER DATABASE ' + DB_NAME() + ' SET SINGLE_USER WITH ROLLBACK IMMEDIATE ;
    ALTER DATABASE ' + DB_NAME() + ' SET READ_COMMITTED_SNAPSHOT ON;
    ALTER DATABASE ' + DB_NAME() + ' SET MULTI_USER;'

    Exec(@sql)
end
Nick Berardi
  • 54,393
  • 15
  • 113
  • 135
  • You should wrap your db_name() calls with quotename(), to account for any characters in the database name that might need escaping (like spaces). – Rick Jan 11 '12 at 17:20
  • you also need 'SET allow_snapshot_isolation ON' right? (see my answer) – Simon_Weaver Dec 05 '12 at 20:38
  • The mssql docs claim that you do need to set allow snapshot isolation. But I'm really glad to find this working answer in an ocean of SQL server noise. – Alkanshel Jun 11 '19 at 01:28
9

I tried the command:

ALTER DATABASE MyDB SET READ_COMMITTED_SNAPSHOT ON
GO

against a dev box but the it took 10+ minutes and so I killed it.

I then found this:

https://willwarren.com/2015/10/12/sql-server-read-committed-snapshot/

and used his code block (which took about 1:26 to run):

USE master
GO

/** 
 * Cut off live connections
 * This will roll back any open transactions after 30 seconds and
 * restricts access to the DB to logins with sysadmin, dbcreator or
 * db_owner roles
 */
ALTER DATABASE MyDB SET RESTRICTED_USER WITH ROLLBACK AFTER 30 SECONDS
GO

-- Enable RCSI for MyDB
ALTER DATABASE MyDB SET READ_COMMITTED_SNAPSHOT ON
GO

-- Allow connections to be established once again
ALTER DATABASE MyDB SET MULTI_USER
GO

-- Check the status afterwards to make sure it worked
SELECT is_read_committed_snapshot_on
FROM sys.databases
WHERE [name] = 'MyDB '
Jeff Mergler
  • 1,384
  • 20
  • 27
3

Try use master database before altering current database.

USE Master
GO

ALTER DATABASE [YourDatabase] SET READ_COMMITTED_SNAPSHOT ON
GO
eLVik
  • 741
  • 7
  • 14
2

I didn't take a second for me when i changed my DB to single user

Yasin Kilicdere
  • 426
  • 6
  • 17
2

All you need to do is this: ALTER DATABASE xyz SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE;

No need to put the database into single user mode. You will rollback uncommitted transactions though.

Wix
  • 51
  • 5
1

With "ROLLBACK IMMEDIATE" it took about 20-30 seconds on my db which is 300GB.

ALTER DATABASE DBNAME SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
Sam Salim
  • 2,145
  • 22
  • 18
0

Try Shut off the other SQL services so that only the SQL server service is running.

Mine ran for 5 minutes then I cancelled it because it was obvious nothing was happening. Its a brand new server so there are no other users connected. I shut off the SQL Reporting Services and then ran it again.. took less than a second to complete.

Jeff
  • 1