SQL Server, de la zero Lecția 39 / 40

sp_BlitzCache și sp_WhoIsActive: ce se întâmplă CHIAR ACUM

sp_WhoIsActive de la Adam Machanic e procedura de răspuns la urgențe. Plus sp_BlitzFirst pentru wait stats la momentul de față.

Sună telefonul la 3 dimineața. „Baza de date e lentă. Totul dă timeout.”

Deschizi laptopul, te conectezi, rulezi o interogare. Îți spune exact ce rulează, cine pe cine blochează, care interogări mănâncă CPU, care așteaptă disc, care țin lock-uri. Petreci următoarele cinci minute omorând sesiunea potrivită și viața revine la normal.

Acea interogare e sp_WhoIsActive. E procedura open-source de 20 de ani a lui Adam Machanic, și e cea mai utilă unealtă de răspuns la urgențe din arsenalul unui DBA. sp_BlitzFirst (parte din First Responder Kit) e versiunea ușor mai prietenoasă de la echipa lui Brent Ozar.

Instalează-le pe ambele. Mulțumește-mi mai târziu.

sp_WhoIsActive: clasica

Adam Machanic a scris-o pe la 2007. E standardul de aur pentru „cine rulează interogări pe serverul meu chiar acum”. Descarcă: whoisactive.com sau caută „sp_WhoIsActive github”.

Instalare: descarcă fișierul .sql, rulează-l pe master (sau pe baza ta DBA).

Apel de bază:

EXEC sp_WhoIsActive;

Returnează un rând per sesiune utilizator activă, cu coloanele:

  • session_id — SPID-ul.
  • start_time — când a început această cerere.
  • sql_text — ce rulează (XML clicabil, deschide interogarea completă).
  • login_name / host_name / program_name — cine apelează.
  • database_name.
  • wait_info — pe ce așteaptă, de cât timp.
  • CPU, reads, writes — utilizarea resurselor de până acum.
  • blocking_session_id — cine blochează această sesiune (dacă e cazul).
  • status — running, suspended etc.

Sortează după CPU sau reads desc; rândurile de sus sunt interogările tale cele mai grele.

Diagnostic într-o linie:

  • wait_info arată LCK_M_X(42) — așteaptă ca sesiunea 42 să elibereze un lock exclusiv.
  • blocking_session_id = 42 — confirmă.
  • Rulează EXEC sp_WhoIsActive @session_id = 42 pentru a vedea ce face 42.
  • Sau omoară 42: KILL 42.

Parametri utili

  • @get_plans = 1 — include XML-ul planului de execuție.
  • @get_locks = 1 — arată toate lock-urile ținute de fiecare sesiune.
  • @find_block_leaders = 1 — sortează sesiunile astfel încât „liderul de blocaj” (cel care provoacă un lanț de blocaje) să fie sus.
  • @sort_order = '[CPU] DESC' — alege sortarea.
  • @get_task_info = 2 — detalii verbose de task.

Combinația mea uzuală în urgență:

EXEC sp_WhoIsActive
    @find_block_leaders = 1,
    @get_plans          = 1,
    @get_locks          = 1;

Tot ce ai nevoie pe un singur ecran.

Logarea sp_WhoIsActive într-un tabel

Pentru monitorizare continuă:

-- Creează tabelul de destinație
DECLARE @schema NVARCHAR(MAX);
EXEC sp_WhoIsActive @return_schema = 1, @schema = @schema OUTPUT;
SET @schema = REPLACE(@schema, '<table_name>', 'DBA.dbo.WhoIsActive_log');
EXEC (@schema);

-- Programează asta prin Agent la fiecare 60 de secunde
DECLARE @dest NVARCHAR(4000) = 'DBA.dbo.WhoIsActive_log';
EXEC sp_WhoIsActive @destination_table = @dest;

Acum ai un log rulant cu tot ce s-a rulat. Când cineva întreabă „ce s-a întâmplat la 2:15?”, știi.

sp_BlitzFirst: fratele „chiar acum”

Echivalentul lui Brent din First Responder Kit. Stil diferit față de sp_WhoIsActive; ambele sunt utile.

USE DBA;
EXEC sp_BlitzFirst;

Rulează 5 secunde implicit, eșantionând wait stats pe fereastra aceea. Îți dă imaginea de moment în loc de distribuția cumulativă a wait stats.

Output-ul e în stilul sp_Blitz, ordonat după prioritate:

  • Top tipuri de wait curente.
  • Interogări lungi în execuție acum.
  • Utilizarea CPU în acest moment.
  • Baza de date cu activitatea cea mai mare.

@SinceStartup = 1 — în loc de eșantion de 5 secunde, arată stats-uri cumulative de la pornirea serverului.

@ExpertMode = 1 — mai multe coloane, diagnostic mai adânc.

Secvența mea implicită de triaj când sună telefonul:

  1. sp_WhoIsActive @find_block_leaders = 1; — cine pe cine blochează?
  2. sp_BlitzFirst @ExpertMode = 1; — pe ce așteptăm, colectiv?
  3. Alege cea mai mare problemă, acționează.

Zece secunde de tastare. În 90% din cazuri, cauza e evidentă din aceste două interogări.

Omorârea unei sesiuni

Când sp_WhoIsActive îți spune că sesiunea 42 ține pe toată lumea blocată:

KILL 42;

Sesiunea face rollback la tranzacția în curs și se deconectează. Toți cei pe care îi bloca se deblochează. Problemă rezolvată.

Atenție: KILL face rollback la tranzacție. Dacă e o tranzacție mare care rulează de o oră, rollback-ul mai poate dura încă o oră. Verifică sys.dm_exec_requests.percent_complete pentru progresul rollback-ului.

Alternativă: KILL N WITH STATUSONLY; — raportează progresul rollback-ului fără a iniția un alt kill.

Nu te teme de KILL. E răspunsul corect pentru interogări scăpate de sub control, tranzacții înțepenite și sesiuni de la un client mort care nu și-a închis niciodată conexiunea.

Cele trei tipuri de sesiuni „zombie” pe care le omori regulat

  1. Sesiuni sleeping cu tranzacții deschise. Cineva a pornit un BEGIN TRAN în SSMS, a plecat la prânz. Conexiunea doarme, dar lock-urile sunt ținute. Omoar-o.
  2. Sesiuni suspended care așteaptă lock pentru totdeauna. Cauza e sesiunea care le blochează; sp_WhoIsActive @find_block_leaders = 1 arată liderul. Omoară-l pe lider.
  3. Procese background care fac lucruri ciudate. Rar. De obicei semnul unei probleme mai adânci. Nu omorî fără discriminare; unele dintre ele sunt fire de execuție interne ale SQL Server.

Bune practici de monitorizare

  • sp_WhoIsActive la fiecare 30–60 de secunde, logat într-un tabel. Rotește log-ul (păstrează 7 zile). Una dintre mișcările de monitorizare cu cel mai mare impact pe care o poți face.
  • Alertă pe „sesiuni blocate de > N secunde”. Rulează sp_WhoIsActive @find_block_leaders = 1 din verificarea de alertă; dacă e un block leader și victima a așteptat > 30 de secunde, dă ping celui de gardă.
  • Pune pe grafic CPU / wait stats din sys.dm_os_ring_buffers ca să ai vizibilitate pe săptămâni, nu doar pe acum.

Rulează asta pe propria mașină

-- 1. Instalează sp_WhoIsActive de pe whoisactive.com
-- 2. Instalează First Responder Kit pentru sp_BlitzFirst

-- 3. Rulează o interogare care durează ceva, într-o sesiune:
BEGIN TRAN;
UPDATE Sales.Customer SET Name = Name + N' (updating)' WHERE CustomerId = 1;
-- Nu face commit. Lasă această sesiune deschisă.

-- 4. În altă sesiune:
EXEC sp_WhoIsActive @find_block_leaders = 1, @get_plans = 1;

-- 5. Vezi starea curentă a waits-urilor
EXEC sp_BlitzFirst;

-- 6. Întoarce-te la sesiunea 1 și fă commit (sau rollback)
COMMIT;

Într-o urgență n-ai ocazia să citești o lecție mai întâi. Exersează aceste unelte pe timp de pace. Memoria musculară e ce te salvează la 3 dimineața.

Următoarea, lecția finală a cursului: un health check de SQL Server în 30 de minute — checklist-ul ordonat pe care îl rulezi pe un server pe care nu l-ai mai văzut. Punând împreună tot din lecțiile 21 până la 40.

Caută