Estou tentando entender por que há uma discrepância na contagem de bloqueios sys.dm_tran_locks
e no sqlserver.lock_acquired
evento estendido em certos casos. Aqui está meu script de reprodução, estou usando o StackOverflow2013
banco de dados no SQL Server 2019 RTM, nível de compatibilidade 150.
/* Initial Setup */
IF OBJECT_ID('dbo.HighQuestionScores', 'U') IS NOT NULL
DROP TABLE dbo.HighQuestionScores;
CREATE TABLE dbo.HighQuestionScores
(
Id INT PRIMARY KEY CLUSTERED,
DisplayName NVARCHAR(40) NOT NULL,
Reputation BIGINT NOT NULL,
Score BIGINT
)
INSERT dbo.HighQuestionScores
(Id, DisplayName, Reputation, Score)
SELECT u.Id,
u.DisplayName,
u.Reputation,
NULL
FROM dbo.Users AS u;
CREATE INDEX ix_HighQuestionScores_Reputation ON dbo.HighQuestionScores (Reputation);
Em seguida, atualizo as estatísticas da tabela com uma grande contagem de linhas falsas
/* Chaotic Evil. */
UPDATE STATISTICS dbo.HighQuestionScores WITH ROWCOUNT = 99999999999999;
DBCC FREEPROCCACHE WITH NO_INFOMSGS;
Então eu abro uma transação e atualizo Score
para Reputação, digamos56
BEGIN TRAN;
UPDATE dbo.HighQuestionScores
SET Score = 1
WHERE Reputation = 56 /* 8066 records */
AND 1 = (SELECT 1);
/* Source: https://www.erikdarlingdata.com/sql-server/helpers-views-and-functions-i-use-in-presentations/ Thanks, Erik */
SELECT *
FROM dbo.WhatsUpLocks(@@SPID) AS wul
WHERE wul.locked_object = N'HighQuestionScores'
ROLLBACK;
Recebo um monte de bloqueios de página (apesar de ter um índice de reputação). Eu estou supondo que as estimativas ruins realmente fizeram um número no otimizador lá.
Eu também verifiquei usando sp_whoisactive
e também retorna as mesmas informações.
<Object name="HighQuestionScores" schema_name="dbo">
<Locks>
<Lock resource_type="OBJECT" request_mode="IX" request_status="GRANT" request_count="1" />
<Lock resource_type="PAGE" page_type="*" index_name="PK__HighQues__3214EC072EE1ADBA" request_mode="X" request_status="GRANT" request_count="6159" />
</Locks>
</Object>
Enquanto isso, eu também tenho um evento estendido acontecendo sqlserver.lock_acquired
separadamente. Quando olho para os dados agrupados, vejo 8066 bloqueios de página em vez dos 6159 iniciais
Definitivamente, não vejo um escalonamento de bloqueio (verificado usando sqlserver.lock_escalation
o evento), então acho que minha pergunta é por que o evento estendido está mostrando uma discrepância com um número maior de contagem de bloqueio?
O XE está relatando um bloqueio de página sendo adquirido cada vez que uma linha é atualizada (um evento para cada uma das 8.066 linhas afetadas pela atualização). No entanto, essas linhas são armazenadas apenas em 6.159 páginas exclusivas, o que explica a discrepância.
Não tenho o StackOverflow2013 nesta máquina, mas tenho uma experiência semelhante com o SO2010:
Você pode ver as mesmas páginas sendo bloqueadas repetidamente na saída do XE se classificar por
resource_0
:Usando
DBCC PAGE
:Eu posso ver que a página 180020 tem 163 registros nela (
m_slotCnt = 163
):E que 3 deles correspondem aos critérios de atualização (colei a saída no notepad ++ e procurei por "Reputação = 56"):
Aqui está a primeira partida, como exemplo:
Acredito que esse comportamento seja devido à natureza em pipeline dos planos de execução e à maneira como esse XE específico é implementado.