Domanda

Da alcune recenti test e la lettura che ho fatto, sembra che la "X" (esclusiva) Nome parte XLOCK è fuorviante. Essa, infatti, non si blocca più di quanto UPDLOCK. Se fosse esclusiva, sarebbe prevenire SELECT esterni, che non è così.

Non riesco a vedere né dalla lettura o dalla sperimentazione e la differenza tra i due.

L'unica XLOCK tempo crea un blocco esclusivo è quando viene utilizzato con TABLOCK. La mia prima domanda è "perché solo in questo granularità?"

Inoltre, mi sono imbattuto in un blog che afferma quanto segue :

  

Tuttavia, attenzione per XLOCK suggerimento. SQL Server ignorerà efficacemente XLOCK suggerimento! C'è un'ottimizzazione dove il check SQL Server se i dati è cambiato da quando la più vecchia transazione aperta. Se no, allora un xlock viene ignorato. Questo rende i suggerimenti xlock sostanzialmente inutile e dovrebbe essere evitato.

Qualcuno ha eseguito attraverso questo fenomeno?

In base a quello che sto vedendo, sembra che questo suggerimento dovrebbe essere ignorato.

È stato utile?

Soluzione

Più esclusivo di serrature X vs U serrature

Nel matrice di compatibilità serratura sotto si può vedere che il blocco X è compatibile solo con la stabilità schema e tipi di blocco Inserire Range-Null. U è compatibile con i seguenti ulteriori tipi di blocco condivise S / IS / RS-S / RI-S / RX-S

matrice serratura compatibilità http: // i. msdn.microsoft.com/ms186396.LockConflictTable(en-us,SQL.105).gif

granularità di X serrature

Questi sono presi tutto bene a tutti i livelli. La sceneggiatura e profiler traccia seguente dimostra che vengano prese con successo a livello di riga.

CREATE TABLE test_table (id int identity(1,1) primary key, col char(40))

INSERT INTO test_table
SELECT NEWID() FROM sys.objects

select * from test_table with (rowlock,XLOCK) where id=10

Trace

Ma le righe si può ancora leggere!

Si scopre che a livello di isolamento read committed SQL Server non sempre togliere le serrature S, si salta questo passaggio se non v'è alcun rischio di leggere dati commit senza . Questo significa che non v'è alcuna garanzia di un conflitto di blocco che si verificano mai.

Tuttavia, se le iniziali Select è with (paglock,XLOCK) allora questo fermare la transazione di lettura come il blocco X sulla pagina bloccherà il blocco di pagina IS che sarà sempre necessaria da parte del lettore. Ciò, naturalmente, hanno un impatto sulla concorrenza.

Altro Avvertimenti

Anche se si blocca la riga / pagina di questo non significa che si bloccano tutti gli accessi a quella riga della tabella. Un blocco su una riga nell'indice cluster non impedirà query lettura dati della riga corrispondente in un indice di copertura non cluster.

Altri suggerimenti

Non è un avvertimento, è un malinteso su ciò che accade nella SELECT.

Un semplice SELEZIONA non richiede blocchi condivisi se le pagine non contengono dati sporchi, e quindi non è bloccato da XLOCK.

Per essere bloccata da XLOCK, è necessario eseguire nel livello di isolamento REPEATABLE LEGGI. Due cose che possono innescare:

  1. Dati Modifica, attraverso INSERT / UPDATE / DELETE. La tabella aggiornata non deve essere quello della XLOCK è acceso.
  2. chiedendo esplicitamente REPEATABLE LEGGI attraverso il livello di isolamento delle transazioni o hint di tabella.

sulla base dei commenti a @ di Martin risposta , ecco un piccolo script (eseguito le diverse parti in diversi SSMS finestre per testare il blocco che impedisce un SELECT:

--
--how to lock/block a SELECT as well as UPDATE/DELETE on a particular row
--

--drop table MyTable
--set up table to test with
CREATE TABLE MyTable (RowID int primary key clustered
                     ,RowValue int unique nonclustered not null) 

--populate test data
;WITH InsertData AS
(
    SELECT 4321 AS Number
    UNION ALL
    SELECT Number+1
        FROM InsertData
        WHERE Number<9322
)
INSERT MyTable
        (RowID,RowValue)
    SELECT
        Number, 98765-Number
        FROM InsertData
        ORDER BY Number
    OPTION (MAXRECURSION 5001)

-----------------------------------------------------------------------------
-- #1
--OPEN A NEW SSMS window and run this
--
--create lock to block select/insert/update/delete
DECLARE @ID int

BEGIN TRANSACTION

SELECT @ID=RowID FROM MyTable WITH (ROWLOCK, XLOCK, HOLDLOCK) WHERE RowID=6822
PRINT @ID

--COMMIT  --<<<only run the commit when you want to release the lock
          --<<<adfter opening the other new windows and running the SQL in them



-----------------------------------------------------------------------------
-- #2
--OPEN A NEW SSMS window and run this
--
--shows how a select must wait for the lock to be released
--I couldn't get SSMS to output any text while in the trnasaction, even though
--it was completing those commands (possibly buffering them?) so look at the
--time to see that the statements were executing, and the SELECT...WHERE RowID=6822
--was what was where this script is blocked and waiting
SELECT GETDATE() AS [start of run]
SELECT '1 of 2, will select row',* FROM MyTable Where RowID=6822
go
DECLARE @SumValue int
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SELECT GETDATE() AS [before transaction, shouldn't be nuch difference]
BEGIN TRANSACTION
SELECT @SumValue=SUM(RowID) FROM MyTable WHERE ROWID<6000
SELECT GETDATE() AS [in transaction, shouldn't be much difference]
    , @SumValue AS SumValue
--everything to here will run immediately, but the select below will wait for the
-- lock to be removed
SELECT '2 of 2, will wait for lock',* FROM MyTable Where RowID=6822
SELECT GETDATE() AS [in transaction after lock was removed, should show a difference]
COMMIT


-----------------------------------------------------------------------------
-- #3
--OPEN A NEW SSMS window and run this
--
--show how an update must wait
UPDATE MyTable SET RowValue=1111 WHERE RowID=5000  --will run immediately
GO
UPDATE MyTable SET RowValue=1111 WHERE RowID=6822 --waits for the lock to be removed

-----------------------------------------------------------------------------
-- #4
--OPEN A NEW SSMS window and run this
--
--show how a delete must wait
DELETE MyTable WHERE RowID=5000 --will run immediately
go
DELETE MyTable WHERE RowID=6822  --waits for the lock to be removed
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top