Hala kilit tutan sorguyu nasıl bulabilirim?


15

Sorgulanıyor sys.dm_tran_locks bize hangi oturumların (SPID) tablo, sayfa ve satır gibi kaynaklarda kilit tuttuğunu gösterir.

Alınan her kilit için hangi SQL ifadesinin (silme, ekleme, güncelleme veya seçme) bu kilide neden olduğunu belirlemenin bir yolu var mı?

Biliyorum ki most_recent_query_handlesütunsys.dm_exec_connectionsDMV bize yürütülen son sorgunun metnini verdiğini , ancak birkaç kez diğer sorgular aynı oturum (SPID) altında daha önce koştu ve hala kilitleri tutuyor.

Zaten sp_whoisactive(Adam Machanic) prosedürü kullanmak ve sadece DBCC INPUTBUFFER @spidher zaman (ve benim durumumda genellikle asla) kilidi edinilen sorgu olan şu anda (düşünmek ) giriş arabellek üzerinde sorgu gösterir .

Örneğin:

  1. açık işlem / oturum
  2. bir ifadeyi yürütme
  3. aynı oturumda başka bir ifade yürüt
  4. başka bir işlem / oturum açın ve 2. adımda kilitli olan kaynağı değiştirmeye çalışın.

sp_whoisactiveProsedür kullanışlı böylece kilit sorumlu değil, değil 3. adımda en ifadeyi işaret edecektir.

Bu soru Engellenen Süreç Raporlarını kullanarak bir analiz yapmaktan geldi , üretimdeki engelleme senaryolarının temel nedenini bulmak için özelliğini . Her işlem birkaç sorgu yürütür ve çoğu zaman sonuncusu (BPR'deki giriş arabelleğinde gösterilen) nadiren kilidi tutan işlemdir.

Takip eden bir sorum var: Engelleme sorgularını etkin bir şekilde tanımlamak için çerçeve

Yanıtlar:


15

SQL Server çalıştırılan komutların geçmişini tutmaz 1,2 . Hangi nesnelerin kilitleri olduğunu belirleyebilirsiniz, ancak bu kilitlerin hangi ifadeye neden olduğunu mutlaka göremezsiniz.

Örneğin, bu ifadeyi yürütürseniz:

BEGIN TRANSACTION
INSERT INTO dbo.TestLock DEFAULT VALUES

Ve SQL Metne en son sql tanıtıcısıyla bakın, ifadenin göründüğünü göreceksiniz. Ancak, oturum bunu yaptıysa:

BEGIN TRANSACTION
INSERT INTO dbo.TestLock DEFAULT VALUES
GO
SELECT *
FROM dbo.TestLock;
GO

SELECT * FROM dbo.TestLock;İşlem yapılmadığı halde ifadeyi yalnızca görürdünüz ve ifade INSERTokuyucuları dbo.TestLocktabloya karşı engelliyor .

Bunu diğer oturumları engelleyen talihsiz işlemleri aramak için kullanıyorum:

/*
    This query shows sessions that are blocking other sessions, including sessions that are 
    not currently processing requests (for instance, they have an open, uncommitted transaction).

    By:  Max Vernon, 2017-03-20
*/
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; --reduce possible blocking by this query.

USE tempdb;

IF OBJECT_ID('tempdb..#dm_tran_session_transactions') IS NOT NULL
DROP TABLE #dm_tran_session_transactions;
SELECT *
INTO #dm_tran_session_transactions
FROM sys.dm_tran_session_transactions;

IF OBJECT_ID('tempdb..#dm_exec_connections') IS NOT NULL
DROP TABLE #dm_exec_connections;
SELECT *
INTO #dm_exec_connections
FROM sys.dm_exec_connections;

IF OBJECT_ID('tempdb..#dm_os_waiting_tasks') IS NOT NULL
DROP TABLE #dm_os_waiting_tasks;
SELECT *
INTO #dm_os_waiting_tasks
FROM sys.dm_os_waiting_tasks;

IF OBJECT_ID('tempdb..#dm_exec_sessions') IS NOT NULL
DROP TABLE #dm_exec_sessions;
SELECT *
INTO #dm_exec_sessions
FROM sys.dm_exec_sessions;

IF OBJECT_ID('tempdb..#dm_exec_requests') IS NOT NULL
DROP TABLE #dm_exec_requests;
SELECT *
INTO #dm_exec_requests
FROM sys.dm_exec_requests;

;WITH IsolationLevels AS 
(
    SELECT v.*
    FROM (VALUES 
              (0, 'Unspecified')
            , (1, 'Read Uncomitted')
            , (2, 'Read Committed')
            , (3, 'Repeatable')
            , (4, 'Serializable')
            , (5, 'Snapshot')
        ) v(Level, Description)
)
, trans AS 
(
    SELECT dtst.session_id
        , blocking_sesion_id = 0
        , Type = 'Transaction'
        , QueryText = dest.text
    FROM #dm_tran_session_transactions dtst 
        LEFT JOIN #dm_exec_connections dec ON dtst.session_id = dec.session_id
    OUTER APPLY sys.dm_exec_sql_text(dec.most_recent_sql_handle) dest
)
, tasks AS 
(
    SELECT dowt.session_id
        , dowt.blocking_session_id
        , Type = 'Waiting Task'
        , QueryText = dest.text
    FROM #dm_os_waiting_tasks dowt
        LEFT JOIN #dm_exec_connections dec ON dowt.session_id = dec.session_id
    OUTER APPLY sys.dm_exec_sql_text(dec.most_recent_sql_handle) dest
    WHERE dowt.blocking_session_id IS NOT NULL
)
, requests AS 
(
SELECT des.session_id
    , der.blocking_session_id
    , Type = 'Session Request'
    , QueryText = dest.text
FROM #dm_exec_sessions des
    INNER JOIN #dm_exec_requests der ON des.session_id = der.session_id
OUTER APPLY sys.dm_exec_sql_text(der.sql_handle) dest
WHERE der.blocking_session_id IS NOT NULL
    AND der.blocking_session_id > 0 
)
, Agg AS (
    SELECT SessionID = tr.session_id
        , ItemType = tr.Type
        , CountOfBlockedSessions = (SELECT COUNT(*) FROM requests r WHERE r.blocking_session_id = tr.session_id)
        , BlockedBySessionID = tr.blocking_sesion_id
        , QueryText = tr.QueryText
    FROM trans tr
    WHERE EXISTS (
        SELECT 1
        FROM requests r
        WHERE r.blocking_session_id = tr.session_id
        )
    UNION ALL
    SELECT ta.session_id
        , ta.Type
        , CountOfBlockedSessions = (SELECT COUNT(*) FROM requests r WHERE r.blocking_session_id = ta.session_id)
        , BlockedBySessionID = ta.blocking_session_id
        , ta.QueryText
    FROM tasks ta
    UNION ALL
    SELECT rq.session_id
        , rq.Type
        , CountOfBlockedSessions =  (SELECT COUNT(*) FROM requests r WHERE r.blocking_session_id = rq.session_id)
        , BlockedBySessionID = rq.blocking_session_id
        , rq.QueryText
    FROM requests rq
)
SELECT agg.SessionID
    , ItemType = STUFF((SELECT ', ' + COALESCE(a.ItemType, '') FROM agg a WHERE a.SessionID = agg.SessionID ORDER BY a.ItemType FOR XML PATH ('')), 1, 2, '')
    , agg.BlockedBySessionID
    , agg.QueryText
    , agg.CountOfBlockedSessions
    , des.host_name
    , des.login_name
    , des.is_user_process
    , des.program_name
    , des.status
    , TransactionIsolationLevel = il.Description
FROM agg 
    LEFT JOIN #dm_exec_sessions des ON agg.SessionID = des.session_id
    LEFT JOIN IsolationLevels il ON des.transaction_isolation_level = il.Level
GROUP BY agg.SessionID
    , agg.BlockedBySessionID
    , agg.CountOfBlockedSessions
    , agg.QueryText
    , des.host_name
    , des.login_name
    , des.is_user_process
    , des.program_name
    , des.status
    , il.Description
ORDER BY 
    agg.BlockedBySessionID
    , agg.CountOfBlockedSessions
    , agg.SessionID;

SSMS'de birkaç sorgu penceresiyle basit bir test yatağı kurarsak, yalnızca en son etkin ifadeyi görebildiğimizi görebiliriz.

İlk sorgu penceresinde şunu çalıştırın:

CREATE TABLE dbo.TestLock
(
    id int NOT NULL IDENTITY(1,1)
);
BEGIN TRANSACTION
INSERT INTO dbo.TestLock DEFAULT VALUES

İkinci pencerede şunu çalıştırın:

SELECT *
FROM  dbo.TestLock

Şimdi, taahhüt edilmeyen engelleme işlemleri sorgusunu yukarıdan çalıştırırsak, aşağıdaki çıktıyı görürüz:

╔═══════════╦═══════════════════════════════╦═════ ═══════════════╦══════════════════════════════════ ═══════╗
║ SessionID ║ ItemType ║ BlockedBySessionID ║ Sorgu Metni ║
╠═══════════╬═══════════════════════════════╬═════ ═══════════════╬══════════════════════════════════ ═══════╣
║ 67 ║ İşlem ║ 0 ║ BAŞLANGIÇ İŞLEMİ ║
Bo ║ ║ ║ dbo.TestLock VARSAYILAN DEĞERLERİNE GİRİN ║
║ 68 ║ Oturum Talebi, Bekleyen Görev ║ 67 ║ SEÇ * ║
Bo ║ ║ ║ dbo.TestLock ock Instagram Hesabındaki Resim ve Videoları dbo.TestLock ║
╚═══════════╩═══════════════════════════════╩═════ ═══════════════╩══════════════════════════════════ ═══════╝

(Sonuçların sonundan bazı alakasız sütunları kaldırdım).

Şimdi, ilk sorgu penceresini şu şekilde değiştirirsek:

BEGIN TRANSACTION
INSERT INTO dbo.TestLock DEFAULT VALUES
GO
SELECT *
FROM dbo.TestLock;
GO

ve 2. sorgu penceresini yeniden çalıştırın:

SELECT *
FROM  dbo.TestLock

Bu çıktıyı engelleme işlemleri sorgusundan göreceğiz:

╔═══════════╦═══════════════════════════════╦═════ ═══════════════╦════════════════════╗
║ SessionID ║ ItemType ║ BlockedBySessionID ║ Sorgu Metni ║
╠═══════════╬═══════════════════════════════╬═════ ═══════════════╬════════════════════╣
║ 67 ║ İşlem ║ 0 ║ SEÇ * ║
Bo ║ ║ ║ bo dbo.TestLock; ║
║ 68 ║ Oturum Talebi, Bekleyen Görev ║ 67 ║ SEÇ * ║
Bo ║ ║ ║ Dbo.TestLock ║ ║
╚═══════════╩═══════════════════════════════╩═════ ═══════════════╩════════════════════╝

1 - tamamen doğru değil . Yordam önbelleği vardır edebilir kilit sorumlu deyimi içerir. Ancak, önbellekte söz konusu kaynağa dokunan birçok sorgu olabileceğinden, hangi ifadenin kilidin asıl nedeni olduğunu belirlemek kolay olmayabilir.

Aşağıdaki sorgu, yordam önbelleğim çok meşgul olmadığından yukarıdaki sınama sorguları için sorgu planını gösterir.

SELECT TOP(30) t.text
    , p.query_plan
    , deqs.execution_count
    , deqs.total_elapsed_time
    , deqs.total_logical_reads
    , deqs.total_logical_writes
    , deqs.total_logical_writes
    , deqs.total_rows
    , deqs.total_worker_time
    , deqs.*
FROM sys.dm_exec_query_stats deqs
OUTER APPLY sys.dm_exec_sql_text(deqs.sql_handle) t 
OUTER APPLY sys.dm_exec_query_plan(deqs.plan_handle) p
WHERE t.text LIKE '%dbo.TestLock%'  --change this to suit your needs
    AND t.text NOT LIKE '/\/\/\/\/EXCLUDE ME/\/\/\/\/\'
ORDER BY 
    deqs.total_worker_time DESC;

Bu sorgunun sonuçları olabilecek böyle yordam önbellek oldukça yoğun bir sistemde zorlu olabilir araştırırken, aşağıdaki suçlu bulmasını sağlamak, ama dikkat edin.

2 SQL Server 2016 ve üzeri teklif Sorgu Mağaza , yapar yürütülen sorguları tam geçmişini korur.


@Max teşekkürler, çok iyi açıkladı. Bu şüphe, Blocked Process Reportsüretimde engelleme senaryolarının temel nedenini bulmak için özellik analizi yapılırken doğdu . Her işlem birkaç sorgu yürütür ve çoğu zaman sonuncusu (BPR'deki giriş arabelleğinde gösterilen) nadiren kilidi tutan işlemdir. Bunu çözmek için son kaynağım, her oturum altında hangi sorguların çalıştığını anlatmak için hafif bir xEvents oturumu ayarlamak gibi görünüyor. Bunun bir örneğini gösteren bir makale biliyorsanız minnettar olacağım.
18:22 tanitelle

Ayrıca Sorgu Deposu ile ilgili olarak, çok yararlıdır, ancak SPID bilgisinden yoksundur. Yine de teşekkürler.
tanitelle


6

Max'in cevabını tamamlamak için aşağıdaki yardımcı programları son derece yararlı buldum:

Beta_lockinfo'yu engellemeye derinlemesine dalmak ve ne ve nasıl engellemenin ortaya çıktığını analiz etmek istediğimde kullanıyorum - ki bu son derece yararlı.

beta_lockinfo süreçler, sahip oldukları kilitler ve aktif işlemleri hakkında bilgi sağlayan saklı bir prosedürdür. beta_lockinfo engelleme durumu hakkında olabildiğince fazla bilgi toplamak için tasarlanmıştır, böylece suçluyu anında bulabilir ve durum umutsuzsa engelleme sürecini öldürebilirsiniz. Ardından, bloke etme durumunun nasıl ortaya çıktığını anlamak ve durumun tekrarlanmasını önlemek için hangi önlemlerin alınacağını anlamak için arkanıza yaslanıp beta_lockinfo çıktısını analiz edebilirsiniz. Beta_lockinfo'nun çıktısı, kilitli pasif süreçlerin yanı sıra hangi nesneleri kilitledikleri, en son hangi komutu gönderdiklerini ve hangi ifadeyi yürüttüklerini gösterir. Mevcut ifadeler için sorgu planları da alırsınız.


1
vay be, Erland Sommarskog proc şaşırtıcı.
Max Vernon

1
Evet, engelleme detaylarına derinlemesine dalmam gerektiğinde kullanıyorum.
Kin Shah
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.