Lock Escalation e Count Discrepancy in lock_acquired Extended Event
Sto cercando di capire perché in alcuni casi c'è una discrepanza nel conteggio dei blocchi sys.dm_tran_lockse sqlserver.lock_acquirednell'evento esteso. Ecco il mio script di repro, sto usando il StackOverflow2013database su SQL Server 2019 RTM, livello di compatibilità 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);
Successivamente aggiorno le statistiche della tabella con un conteggio di righe false di grandi dimensioni
/* Chaotic Evil. */
UPDATE STATISTICS dbo.HighQuestionScores WITH ROWCOUNT = 99999999999999;
DBCC FREEPROCCACHE WITH NO_INFOMSGS;
Quindi apro una transazione e aggiorno Scoreper Reputazione, ad esempio56
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;
Ottengo un sacco di blocchi di pagina (nonostante abbia un indice sulla reputazione). Immagino che le stime sbagliate abbiano davvero fatto un numero sull'ottimizzatore lì.
Ho anche ricontrollato usando sp_whoisactivee anch'esso restituisce le stesse informazioni.
<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>
Nel frattempo ho anche un evento esteso in esecuzione sqlserver.lock_acquiredseparatamente. Quando guardo i dati raggruppati vedo 8066 blocchi di pagina invece di 6159 iniziali
Sicuramente non vedo un'escalation di blocchi (verificata utilizzando l' sqlserver.lock_escalationevento), quindi immagino che la mia domanda sia perché l'evento esteso mostra una discrepanza con un numero maggiore di conteggi di blocchi?
Risposte
XE segnala l'acquisizione di un blocco di pagina ogni volta che viene aggiornata una riga (un evento per ciascuna delle 8066 righe interessate dall'aggiornamento). Tuttavia, queste righe vengono memorizzate solo su 6159 pagine univoche, il che spiega la discrepanza.
Non ho StackOverflow2013 su questa macchina, ma ho un'esperienza simile con SO2010:
- 1368 righe aggiornate (e altrettanti XEvents attivati)
- 958 blocchi di pagine
Puoi vedere le stesse pagine bloccate ripetutamente nell'output XE se ordini per resource_0:
Utilizzando DBCC PAGE:
DBCC TRACEON (3604); -- needed for the next one to work
GO
DBCC PAGE (StackOverflow2010, 1, 180020, 3);
GO
Vedo che la pagina 180020 contiene 163 record ( m_slotCnt = 163):
Page @0x000002C278C62000
m_pageId = (1:180020) m_headerVersion = 1 m_type = 1
m_typeFlagBits = 0x0 m_level = 0 m_flagBits = 0x0
m_objId (AllocUnitId.idObj) = 174 m_indexId (AllocUnitId.idInd) = 256
Metadata: AllocUnitId = 72057594049331200
Metadata: PartitionId = 72057594044350464 Metadata: IndexId = 1
Metadata: ObjectId = 1525580473 m_prevPage = (1:180019) m_nextPage = (1:180021)
pminlen = 24 m_slotCnt = 163 m_freeCnt = 31
m_freeData = 7835 m_reservedCnt = 0 m_lsn = (203:19986:617)
m_xactReserved = 0 m_xdesId = (0:0) m_ghostRecCnt = 0
m_tornBits = 1894114769 DB Frag ID = 1
E quei 3 di questi corrispondono ai criteri di aggiornamento (ho incollato l'output in Notepad ++ e ho cercato "Reputation = 56"):
Ecco la prima corrispondenza, come esempio:
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS
Record Size = 39
Memory Dump @0x000000EDB2B7821D
0000000000000000: 30001800 86540000 38000000 00000000 6041c2e4 0...T..8.......`AÂä
0000000000000014: c3020000 04000801 00270045 00720069 006300 Ã........'.E.r.i.c.
Slot 9 Column 1 Offset 0x4 Length 4 Length (physical) 4
Id = 21638
Slot 9 Column 2 Offset 0x1f Length 8 Length (physical) 8
DisplayName = Eric
Slot 9 Column 3 Offset 0x8 Length 8 Length (physical) 8
Reputation = 56
Slot 9 Column 4 Offset 0x0 Length 0 Length (physical) 0
Score = [NULL]
Slot 9 Offset 0x0 Length 0 Length (physical) 0
KeyHashValue = (e1caffa60313)
Slot 10 Offset 0x244 Length 43
Credo che questo comportamento sia dovuto alla natura pipeline dei piani di esecuzione e al modo in cui viene implementato questo XE specifico.