INF: Locking Behavior of Cursors on SQL Server Version 6.0

Last reviewed: April 30, 1997
Article ID: Q132037

The information in this article applies to:
  • Microsoft SQL Server, version 6.0

SUMMARY

Microsoft SQL Server version 6.0 has implemented server cursors and a user controllable setting for TRANSACTION ISOLATION LEVEL. When used together, it can be useful to know the expected locking behavior.

MORE INFORMATION

This document attempts to clarify the effect of optimizer hints and isolation levels on the locking considerations of cursors. The nonlocking parts of optimizer hints affect the cursor behavior in the following ways:

  • INDEX = index_name: If the given index is unique, then this index will be used as the primary keyset for the given table. If the index is not unique, then this optimizer hint will be ignored.

    NOTE: Use of this option may cause dynamic cursors to convert to keyset based cursors if the index chosen does not match the 'ORDER BY' columns in the cursor statement exactly.

  • FASTFIRSTROW: Dynamic cursors will always use this option whenever the primary keyset values chosen is from a nonclustered index. For keyset based cursors this option will be honored if used in the cursor statement, not if not given. The locking related parts of optimizer hints and isolation levels will affect cursor locking behavior as follows:
  • All exclusive locks and table locks (TABLOCK and TABLOCKX) are taken and maintained inside a user transaction. These are held as long as the transaction is open (even if the cursor closes) and released when the transaction ends. If there are no transactions outstanding the TABLOCKX and TABLOCK options will only have read duration, i.e. the table lock will be taken while the rows are being read and released immediately as soon as the read is complete.
  • The isolation level at the time of cursor declare will be in effect throughout the cursor. Changes made to the isolation level after the cursor is declared will not affect the locking behavior.
  • The PAGELOCK keyword is ignored in cursor declare statements.
  • If a certain optimizer locking hint is used for a given table in a cursor statement, it will override isolation level and cursor concurrency option for that table. For example you can open a cursor with the LOCKCC option and specify NOLOCK option on one of the tables participating in the cursor select statement. This will cause that table to be read uncommitted (with no locks) while other tables are protected by update locks.
  • No data modifications (update, delete, insert) can be made to tables that have the NOLOCK optimizer hint.
  • If no optimizer locking hint is used, the isolation level locking will take effect on the cursor if the cursor is opened with OPTCC, OPTCCVAL, or READONLY concurrency options. If the cursor is opened with the LOCKCC option, this option will override isolation level locking.
  • OPTCC, OPTVAL, and LOCKCC concurrency options are disallowed in cursors when isolation level is 0. Also UPDLOCK and TABLOCKX keywords are disallowed as optimizer hints when at this isolation level.
  • If isolation level is 0 during cursor declaration, ANSI cursors will be opened READ ONLY. Extended procedure cursors will fail to open unless READ ONLY option is specified.

The following page gives a detailed table of the kinds of locks taken with various hints and isolation levels. Some of the shorthand terminology is explained below:

RDL - Read locks: These are shared page locks that are taken while the pages are being read and released immediately after the page read is complete.

SCR -Scroll locks: These locks are taken by the cursor fetch command on pages that the rows are returned from. These locks will remain in place as long as the last fetch command has rows fetched from these pages; and released either when a succeeding fetch scrolls off these pages or the cursor is closed. These locks come in two varieties: shared SCR(sh), and update SCR(up) page locks. Only the locks on the data pages will be kept, no locks on the index pages will be taken. Furthermore, if SCROLL locking is in effect on the cursor (shared or update) and there is an outstanding transaction in effect during opening of a keyset based cursor, shared locks will be accumulated on pages generating the keyset and these locks will be kept until the transaction ends.

XT/C Locks: These page locks are taken by the cursor fetch command on pages that the rows are returned from. If a transaction is outstanding, these locks will be kept within the duration of the transaction and released when the transaction commits or rolls back. If there are no transactions, these locks will be kept as long as the cursor is open, or a new transaction is started and then ended. These locks also have shared and update varieties. XT/C(sh) and XT/C(up) for page locks

XT(tb) and XT(tbx): Shared and exclusive table locks. These locks can only be taken inside a transaction and can only live within the life of the transaction, not the cursor.

The following table attempts to clarify in detail what kind of locks will be taken with cursors under different locking hints and optimizer levels:

TABLE OPTIMIZER HINT

Cursor       Isolation
Concurr.      Level   No hints    NOLOCK    HOLDLOCK   UPDLOCK
Option ___________________________________________________________________
OPTCC       Uncomm.
OPTVAL        (0)       Disallowed Disallowed Disallowed Disallowed
   -----------------------------------------------------------
Comtd.
              (1)       RDL         NONE      SCR(sh)    SCR(up)
   -----------------------------------------------------------
            Serial/rpt
              (2)       SCR(sh)     NONE      SCR(sh)    SCR(up)
                        XT/C(sh)              XT/C(sh)   XT/C(up)
___________________________________________________________________
LOCKCC      Uncomm.
              (0)       Disallowed Disallowed Disallowed Disallowed

            Comtd.
              (1)       SCR(up)    NONE       SCR(up)    SCR(up)
            Serial/rpt
              (2)       SCR(up)    NONE       SCR(up)    SCR(up)
                        XT/C(up)              XT/C(up)   XT/C(up)
___________________________________________________________________
READ        Uncomm.
ONLY          (0)       NONE       NONE       SCR(sh)    Disallowed
            Comtd.
              (1)       RDL        NONE       SCR(sh)    Disallowed
            Serial/rpt
              (2)       SCR(sh)    NONE       SCR(sh)    Disallowed
                        XT/C(sh)              XT/C(sh)
___________________________________________________________________

Part 2 TABLE OPTIMIZER HINT

Cursor       Isolation
Concurr.     Level        TABLOCK          TABLOCKX
Option ___________________________________________________________
OPTCC        Uncomm.
OPTVAL        (0)         Disallowed      Disallowed
             Comtd.     (inside xact only) (inside xact only)
              (1)         XT(tb)            XT(tbx)
             Serial/rpt
              (2)       (inside xact only) (inside xact only)
                          XT(tb)            XT(tbx)
____________________________________________________________
LOCKCC       Uncomm.
              (0)         Disallowed        Disallowed
             Comtd.     (inside xact only) (inside xact only)
              (1)         XT(tb)            XT(tbx)
             Serial/rpt
              (2)       (inside xact only) (inside xact only)
                          XT(tb)            XT(tbx)
____________________________________________________________
READ         Uncomm.
ONLY          (0)        NONE               Disallowed
             Comtd.
              (1)        NONE               Disallowed
             Serial/rpt
              (2)       (inside xact only)  Disallowed
                          XT(tb)
________________________________________________________

NOTE: The above two tables should also fit side by side into one table.


Additional query words: Windows NT sql6 cursor lock concurrency
Keywords : kbusage SSrvWinNT
Version : 6.0
Platform : WINDOWS


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: April 30, 1997
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.