SQL Server engelleme sorunlarını anlama ve çözme

Şunlar için geçerlidir: SQL Server (desteklenen tüm sürümler), Azure SQL Yönetilen Örneği

Orijinal KB numarası: 224453

Amaç

Makalede SQL Server'da engelleme açıklanmakta ve engelleme sorunlarını giderme ve çözme adımları gösterilmektedir.

Bu makalede bağlantı terimi, veritabanının tek bir oturum açılmış oturumunu ifade eder. Her bağlantı, birçok DMV'de oturum kimliği (SPID) veya session_id olarak görünür. Her zamanki anlamda ayrı bir işlem bağlamı olmasa da genellikle bu SPID'lerin her biri işlem olarak adlandırılır. Daha doğrusu, her SPID, belirli bir istemciden gelen tek bir bağlantının isteklerine hizmet vermek için gereken sunucu kaynaklarından ve veri yapılarından oluşur. Tek bir istemci uygulamasının bir veya daha fazla bağlantısı olabilir. SQL Server açısından bakıldığında, tek bir istemci bilgisayarda tek bir istemci uygulamasından birden çok bağlantı ile birden çok istemci uygulamasından veya birden çok istemci bilgisayardan birden çok bağlantı arasında fark yoktur; bunlar atomiktir. Bir bağlantı, kaynak istemciden bağımsız olarak başka bir bağlantıyı engelleyebilir.

Not

Bu makale, Azure SQL Yönetilen Örnekler de dahil olmak üzere SQL Server örneklerine odaklanmıştır. Azure SQL Veritabanında engelleme sorunlarını gidermeye özgü bilgiler için bkz. Azure SQL Veritabanı engelleme sorunlarını anlama ve çözme.

Engelleme nedir

Engelleme, kilit tabanlı eşzamanlılığa sahip ilişkisel veritabanı yönetim sisteminin (RDBMS) kaçınılmaz ve tasarım gereği bir özelliğidir. Daha önce belirtildiği gibi, SQL Server'da bir oturum belirli bir kaynakta kilit tuttuğunda ve ikinci bir SPID aynı kaynakta çakışan bir kilit türü elde etmeye çalıştığında engelleme gerçekleşir. İlk SPID'nin kaynağı kilitlediği zaman dilimi genellikle kısadır. Sahibi olan oturum kilidi serbest bıraktığı zaman, ikinci bağlantı kaynak üzerinde kendi kilidini almak ve işlem yapmaya devam etmek için serbest kalır. Burada açıklandığı gibi, engelleme normal bir davranıştır ve sistem performansı üzerinde fark edilebilir bir etkisi olmaksızın gün boyunca birçok kez gerçekleşebilir.

Sorgunun süresi ve işlem bağlamı, kilitlerinin ne kadar süre tutulduğunu ve böylece diğer sorgular üzerindeki etkisini belirler. Sorgu bir işlem içinde yürütülmezse (ve hiçbir kilit ipucu kullanılmazsa) SELECT deyimleri için kilitler sorgu sırasında değil, yalnızca okunduğu sırada kaynakta tutulur. INSERT, UPDATE ve DELETE deyimlerinde, hem veri tutarlılığı hem de gerekirse sorgunun geri alınmasına izin vermek için kilitler sorgu sırasında tutulur.

Bir işlem içinde yürütülen sorgularda kilitlerin tutulduğu süre, sorgu türüne, işlem yalıtım düzeyine ve sorguda kilit ipuçlarının kullanılıp kullanılmadığına göre belirlenir. Kilitleme, kilit ipuçları ve işlem yalıtım düzeylerinin açıklaması için aşağıdaki makalelere bakın:

Kilitleme ve engelleme, sistem performansı üzerinde olumsuz bir etkiye neden olan bir noktaya kadar devam ettiğinde, bunun nedeni aşağıdakilerden biridir:

  • SPID, bir kaynak kümesini bırakmadan önce uzun bir süre kilitli tutar. Bu engelleme türü zaman içinde kendi kendine çözülür, ancak performans düşüşlerine neden olabilir.

  • SPID, bir kaynak kümesini kilitli tutar ve hiçbir zaman bırakmaz. Bu engelleme türü kendi kendine çözülmez ve etkilenen kaynaklara erişimi süresiz olarak engeller.

İlk senaryoda, farklı SPID'ler zaman içinde farklı kaynaklarda engellemeye neden olduğundan ve hareketli bir hedef oluşturduğundan durum çok akıcı olabilir. Sorunu tek tek sorgulara daraltmak için SQL Server Management Studio kullanarak bu durumlarla ilgili sorunları gidermek zordur. Buna karşılık, ikinci durum tanılanması daha kolay olabilecek tutarlı bir durumla sonuçlanır.

Uygulamalar ve engelleme

Bir engelleme sorunuyla karşılaşırken sunucu tarafı ayarlama ve platform sorunlarına odaklanma eğilimi olabilir. Ancak, yalnızca veritabanına odaklanmak bir çözüme götürmeyebilir ve istemci uygulaması ve gönderdiği sorgular incelenerek zaman ve enerji daha iyi kullanılabilir. Uygulamanın yapılan veritabanı çağrılarıyla ilgili olarak ne düzeyde görünürlük sunduğundan bağımsız olarak, yine de engelleme sorunu sıklıkla hem uygulama tarafından gönderilen tam SQL deyimlerinin incelenmesini hem de uygulamanın sorgu iptali, bağlantı yönetimi, tüm sonuç satırlarını getirme vb. ile ilgili tam davranışını gerektirir. Geliştirme aracı; bağlantı yönetimi, sorgu iptali, sorgu zaman aşımı, sonuç getirme vb. üzerinde açık denetime izin vermiyorsa engelleme sorunları çözülemeyebilir. Özellikle performansa duyarlı OLTP ortamlarında SQL Server için bir uygulama geliştirme aracı seçmeden önce bu olasılık yakından incelenmelidir.

Veritabanı ve uygulamanın tasarım ve oluşturma aşamasında veritabanı performansına dikkat edin. Özellikle kaynak tüketimi, yalıtım düzeyi ve işlem yolu uzunluğu her sorgu için değerlendirilmelidir. Her sorgu ve işlem mümkün olduğunca basit olmalıdır. İyi bir bağlantı yönetimi disiplini uygulanmalıdır, bu olmadan uygulama düşük sayıda kullanıcıyla kabul edilebilir bir performansa sahip gibi görünebilir ancak kullanıcı sayısı arttıkça performans önemli ölçüde düşebilir.

Düzgün uygulama ve sorgu tasarımıyla SQL Server, çok az engellemeyle aynı anda binlerce kullanıcıyı tek bir sunucuda destekleyebilecek özelliktedir.

Engelleme sorunlarını giderme

Hangi engelleme durumunda olduğumuzdan bağımsız olarak, kilitleme sorunlarını giderme metodolojisi aynıdır. Bu mantıksal ayrımlar, bu makalenin geri kalanını dikte edecektir. Konsept, ana engelleyiciyi bulmak ve sorgunun ne yaptığını ve neden engellendiğini belirlemektir. Sorunlu sorgu belirlendikten sonra (yani uzun süre kilitli tutan şey), sonraki adım engellemenin neden gerçekleştiğini analiz etmek ve belirlemektir. Bunun nedenini anladıktan sonra, sorguyu ve işlemi yeniden tasarlayarak değişiklikler yapabiliriz.

Sorun giderme adımları:

  1. Ana engelleme oturumunu tanımlama (baş engelleyici)

  2. Engellemeye neden olan sorguyu ve işlemi bulun (uzun bir süre kilitli tutan şey)

  3. Uzun süreli engellemenin neden gerçekleştiğini analiz etme/anlama

  4. Sorguyu ve işlemi yeniden tasarlayarak engelleme sorununu çözme

Şimdi de uygun bir veri yakalama ile ana engelleme oturumunu nasıl tespit edeceğimizi tartışalım.

Engelleme bilgilerini toplama

Engelleme sorunlarını giderme zorluğunu gidermek için bir veritabanı yöneticisi, SQL Server'da kilitleme ve engelleme durumunu sürekli izleyen SQL betiklerini kullanabilir. Bu verileri toplamak için iki ücretsiz yöntem vardır.

İlki, dinamik yönetim nesnelerini (DMO'lar) sorgulamak ve sonuçları zaman içinde karşılaştırmak üzere depolamaktır. Bu makalede başvuruda bulunan bazı nesneler dinamik yönetim görünümleri (DMV) ve bazıları dinamik yönetim işlevleridir (DDF).

İkincisi, yürütülenleri yakalamak için Genişletilmiş Olaylar (XEvents) veya SQL Profiler İzlemeleri kullanmaktır. SQL İzleme ve SQL Server Profiler kullanım dışı bırakıldığından, bu sorun giderme kılavuzu XEvents'e odaklanır.

DMV'lerden bilgi toplama

Engelleme sorunlarını gidermek için DMV'lere başvurmak, engelleme zincirinin başındaki SPID'yi (oturum kimliği) ve SQL Deyimini tanımlamayı hedeflemektedir. Engellenen kurban SPID'lerini arayın. Herhangi bir SPID başka bir SPID tarafından engelleniyorsa kaynağa sahip olan SPID'yi (engelleyen SPID) araştırın. Bu sahip SPID de engelleniyor mu? Ana engelleyiciyi bulmak için zincirde ilerleyebilir ve ardından neden kilitlediğini araştırabilirsiniz.

Bunu yapmak için aşağıdaki yöntemlerden birini kullanabilirsiniz:

  • SQL Server Management Studio (SSMS) Nesne Gezgini'nde üst düzey sunucu nesnesine sağ tıklayın, Raporlar'ı genişletin, Standart Raporlar'ı genişletin ve ardından Etkinlik – Tüm Engelleme İşlemleri'ni seçin. Bu rapor, bir engelleme zincirinin başındaki güncel işlemleri gösterir. İşlemi genişletirseniz rapor, baş işlem tarafından engellenen işlemleri gösterir. Bu rapor, Engellenen SQL Deyimini ve Engellenmiş SQL Deyimini de gösterir.

  • SSMS'de Etkinlik İzleyicisi'ni açın ve Engelleyen sütununa bakın. Etkinlik İzleyicisi hakkında daha fazla bilgiyi burada bulabilirsiniz.

DMV'ler kullanılarak daha ayrıntılı sorgu tabanlı yöntemler de mevcuttur:

  • sp_who ve sp_who2 komutları, tüm geçerli oturumları gösteren eski komutlardır. DMV sys.dm_exec_sessions, bir sonuç kümesinde sorgulayıp filtrelemesi daha kolay olan daha fazla veri döndürür. Diğer sorguların çekirdeğinde sys.dm_exec_sessions bulacaksınız.

  • Zaten belirli bir oturum tanımladıysanız, bir oturum tarafından gönderilen son deyimi bulmak için DBCC INPUTBUFFER(<session_id>) kullanabilirsiniz. Benzer sonuçlar, sys.dm_exec_input_buffer dinamik yönetim işlevi (DMF) ile sorgulanması ve filtrelenmesi daha kolay bir sonuç kümesinde session_id ve request_id sağlanarak döndürülebilir. Örneğin, session_id 66 ve request_id 0 tarafından gönderilen en son sorguyu döndürmek için:

SELECT * FROM sys.dm_exec_input_buffer (66,0);
  • sys.dm_exec_requests sütununa bakın ve blocking_session_id sütununa başvurun. blocking_session_id = 0 olduğunda, bir oturum engellenmiyordur. sys.dm_exec_requests, yalnızca yürütülmekte olan istekleri listelerken, herhangi bir bağlantı (etkin veya değil) sys.dm_exec_sessions içinde listelenir. Sonraki sorguda sys.dm_exec_requests ile sys.dm_exec_sessions arasındaki bu ortak birleştirme üzerine oluşturun. sys.dm_exec_requests tarafından döndürülmek için sorgunun SQL Server ile etkin bir şekilde yürütülmesi gerektiğini unutmayın.

  • sys.dm_exec_sql_text veya sys.dm_exec_input_buffer DMV'lerini kullanarak etkin olarak yürütülen sorguları ve geçerli SQL toplu metin veya giriş arabellek metnini bulmak için bu örnek sorguyu çalıştırın. sys.dm_exec_sql_text sütununun text öğesi tarafından döndürülen veriler NULL ise sorgu o anda yürütülmüyordur. Bu durumda, sys.dm_exec_input_buffer sütununun event_info sütunu SQL motoruna geçirilen son komut dizesini içerecektir. Bu sorgu, session_id başına engellenen session_id'ler listesi de dahil olmak üzere diğer oturumları engelleyen oturumları belirlemek için de kullanılabilir.

WITH cteBL (session_id, blocking_these) AS 
(SELECT s.session_id, blocking_these = x.blocking_these FROM sys.dm_exec_sessions s 
CROSS APPLY    (SELECT isnull(convert(varchar(6), er.session_id),'') + ', '  
                FROM sys.dm_exec_requests as er
                WHERE er.blocking_session_id = isnull(s.session_id ,0)
                AND er.blocking_session_id <> 0
                FOR XML PATH('') ) AS x (blocking_these)
)
SELECT s.session_id, blocked_by = r.blocking_session_id, bl.blocking_these
, batch_text = t.text, input_buffer = ib.event_info, * 
FROM sys.dm_exec_sessions s 
LEFT OUTER JOIN sys.dm_exec_requests r on r.session_id = s.session_id
INNER JOIN cteBL as bl on s.session_id = bl.session_id
OUTER APPLY sys.dm_exec_sql_text (r.sql_handle) t
OUTER APPLY sys.dm_exec_input_buffer(s.session_id, NULL) AS ib
WHERE blocking_these is not null or r.blocking_session_id > 0
ORDER BY len(bl.blocking_these) desc, r.blocking_session_id desc, r.session_id;
  • Microsoft Desteği tarafından sağlanan bu daha ayrıntılı örnek sorguyu çalıştırarak, bir engelleme zincirinde yer alan oturumların sorgu metni de dahil olmak üzere birden çok oturum engelleme zincirinin başını tanımlayın.
WITH cteHead ( session_id,request_id,wait_type,wait_resource,last_wait_type,is_user_process,request_cpu_time
,request_logical_reads,request_reads,request_writes,wait_time,blocking_session_id,memory_usage
,session_cpu_time,session_reads,session_writes,session_logical_reads
,percent_complete,est_completion_time,request_start_time,request_status,command
,plan_handle,sql_handle,statement_start_offset,statement_end_offset,most_recent_sql_handle
,session_status,group_id,query_hash,query_plan_hash) 
AS ( SELECT sess.session_id, req.request_id, LEFT (ISNULL (req.wait_type, ''), 50) AS 'wait_type'
    , LEFT (ISNULL (req.wait_resource, ''), 40) AS 'wait_resource', LEFT (req.last_wait_type, 50) AS 'last_wait_type'
    , sess.is_user_process, req.cpu_time AS 'request_cpu_time', req.logical_reads AS 'request_logical_reads'
    , req.reads AS 'request_reads', req.writes AS 'request_writes', req.wait_time, req.blocking_session_id,sess.memory_usage
    , sess.cpu_time AS 'session_cpu_time', sess.reads AS 'session_reads', sess.writes AS 'session_writes', sess.logical_reads AS 'session_logical_reads'
    , CONVERT (decimal(5,2), req.percent_complete) AS 'percent_complete', req.estimated_completion_time AS 'est_completion_time'
    , req.start_time AS 'request_start_time', LEFT (req.status, 15) AS 'request_status', req.command
    , req.plan_handle, req.[sql_handle], req.statement_start_offset, req.statement_end_offset, conn.most_recent_sql_handle
    , LEFT (sess.status, 15) AS 'session_status', sess.group_id, req.query_hash, req.query_plan_hash
    FROM sys.dm_exec_sessions AS sess
    LEFT OUTER JOIN sys.dm_exec_requests AS req ON sess.session_id = req.session_id
    LEFT OUTER JOIN sys.dm_exec_connections AS conn on conn.session_id = sess.session_id 
    )
, cteBlockingHierarchy (head_blocker_session_id, session_id, blocking_session_id, wait_type, wait_duration_ms,
wait_resource, statement_start_offset, statement_end_offset, plan_handle, sql_handle, most_recent_sql_handle, [Level])
AS ( SELECT head.session_id AS head_blocker_session_id, head.session_id AS session_id, head.blocking_session_id
    , head.wait_type, head.wait_time, head.wait_resource, head.statement_start_offset, head.statement_end_offset
    , head.plan_handle, head.sql_handle, head.most_recent_sql_handle, 0 AS [Level]
    FROM cteHead AS head
    WHERE (head.blocking_session_id IS NULL OR head.blocking_session_id = 0)
    AND head.session_id IN (SELECT DISTINCT blocking_session_id FROM cteHead WHERE blocking_session_id != 0)
    UNION ALL
    SELECT h.head_blocker_session_id, blocked.session_id, blocked.blocking_session_id, blocked.wait_type,
    blocked.wait_time, blocked.wait_resource, h.statement_start_offset, h.statement_end_offset,
    h.plan_handle, h.sql_handle, h.most_recent_sql_handle, [Level] + 1
    FROM cteHead AS blocked
    INNER JOIN cteBlockingHierarchy AS h ON h.session_id = blocked.blocking_session_id and h.session_id!=blocked.session_id --avoid infinite recursion for latch type of blocking
    WHERE h.wait_type COLLATE Latin1_General_BIN NOT IN ('EXCHANGE', 'CXPACKET') or h.wait_type is null
    )
SELECT bh.*, txt.text AS blocker_query_or_most_recent_query 
FROM cteBlockingHierarchy AS bh 
OUTER APPLY sys.dm_exec_sql_text (ISNULL ([sql_handle], most_recent_sql_handle)) AS txt;
SELECT [s_tst].[session_id],
[database_name] = DB_NAME (s_tdt.database_id),
[s_tdt].[database_transaction_begin_time], 
[sql_text] = [s_est].[text] 
FROM sys.dm_tran_database_transactions [s_tdt]
INNER JOIN sys.dm_tran_session_transactions [s_tst] ON [s_tst].[transaction_id] = [s_tdt].[transaction_id]
INNER JOIN sys.dm_exec_connections [s_ec] ON [s_ec].[session_id] = [s_tst].[session_id]
CROSS APPLY sys.dm_exec_sql_text ([s_ec].[most_recent_sql_handle]) AS [s_est];
  • SQL Server iş parçacığı/görev katmanındaki sys.dm_os_waiting_tasks'a başvurun. Bu, isteğin şu anda hangi SQL wait_type tecrübe ettiği hakkında bilgi döndürür. sys.dm_exec_requests gibi, sys.dm_os_waiting_tasks tarafından yalnızca etkin istekler döndürülür.

Not

Zaman içinde toplanan bekleme istatistikleri de dahil olmak üzere bekleme türleri hakkında daha fazla bilgi için bkz. DMV sys.dm_db_wait_stats.

  • Sorgular tarafından hangi kilitlerin yerleştirildiği hakkında daha ayrıntılı bilgi için sys.dm_tran_locks DMV'sini kullanın. Bu DMV, üretim SQL Server örneğinde büyük miktarlarda veri döndürebilir ve şu anda hangi kilitlerin tutulacağını tanılamak için kullanışlıdır.

sys.dm_os_waiting_tasks üzerindeki INNER JOIN nedeniyle aşağıdaki sorgu, sys.dm_tran_locks çıkışını yalnızca şu anda engellenen isteklerle, bekleme durumlarıyla ve kilitleriyle kısıtlar:

SELECT table_name = schema_name(o.schema_id) + '.' + o.name
, wt.wait_duration_ms, wt.wait_type, wt.blocking_session_id, wt.resource_description
, tm.resource_type, tm.request_status, tm.request_mode, tm.request_session_id
FROM sys.dm_tran_locks AS tm
INNER JOIN sys.dm_os_waiting_tasks as wt ON tm.lock_owner_address = wt.resource_address
LEFT OUTER JOIN sys.partitions AS p on p.hobt_id = tm.resource_associated_entity_id
LEFT OUTER JOIN sys.objects o on o.object_id = p.object_id or tm.resource_associated_entity_id = o.object_id
WHERE resource_database_id = DB_ID()
AND object_name(p.object_id) = '<table_name>';

DMV'lerle, sorgu sonuçlarının zaman içinde depolanması, kalıcı engellemeyi veya eğilimleri belirlemek için belirli bir zaman aralığında engellemeyi gözden geçirmenizi sağlayacak veri noktaları sağlar. CSS'nin bu tür sorunları gidermeye yönelik başvurulacak aracı, PSSDiag veri toplayıcısını kullanmaktır. Bu araç, zaman içinde yukarıda bahsedilen DMV'lerden sonuç kümelerini toplamak için "SQL Server Performans İstatistikleri"ni kullanır. Bu araç sürekli geliştiğinden, GitHub'da DiagManager'ın en son genel sürümünü gözden geçirin.

Genişletilmiş olaylardan bilgi toplama

Yukarıdaki bilgilere ek olarak, SQL Server engelleme sorununu ayrıntılı bir şekilde araştırmak için genellikle sunucudaki etkinliklerin bir izlemesinin yakalanması gerekir. Örneğin, bir oturum bir işlem içinde birden çok deyim yürütürse, yalnızca gönderilen son deyim temsil edilir. Ancak, kilitlerin hala tutulmasının nedeni önceki deyimlerden biri olabilir. İzleme, geçerli işlemdeki bir oturum tarafından yürütülen tüm komutları görmenizi sağlar.

SQL Server'da izlemeleri yakalamanın iki yolu vardır; Genişletilmiş Olaylar (XEvents) ve Profil Oluşturucu İzlemeleri. Ancak SQL Server Profiler kullanan SQL izlemeleri kullanım dışıdır. XEvents, daha fazla çok yönlülük ve gözlemlenen sisteme daha az etki sağlayan daha yeni, daha üstün izleme platformudur ve arabirimi SSMS ile tümleştirilmiştir.

XEvent Profiler menüsünün altındaki Nesne Gezgini'nde listelenmiş, SSMS'de başlamaya hazır önceden hazırlanmış Genişletilmiş Olay oturumları vardır. Daha fazla bilgi için bkz. XEvent Profiler. Ayrıca, SSMS'de kendi özel Genişletilmiş Olay oturumlarınızı oluşturabilirsiniz; bkz. Genişletilmiş Olaylar Yeni Oturum Sihirbazı. Engelleme sorunlarını gidermek için genellikle şunları yakalarız:

  • Kategori Hataları:
    • Dikkat
    • Blocked_process_report**
    • Error_reported (Kanal Yöneticisi)
    • Exchange_spill
    • Execution_warning

**Engellenen işlem raporlarının oluşturulacağı eşiği ve sıklığı yapılandırmak için sp_configure komutunu kullanarak saniyeler içinde engellenen işlem eşiği seçeneğini yapılandırın. Varsayılan olarak engellenen işlem raporları üretilmez.

  • Kategori Uyarıları:

    • Hash_warning
    • Missing_column_statistics
    • Missing_join_predicate
    • Sort_warning
  • Kategori Yürütme:

    • Rpc_completed
    • Rpc_starting
    • Sql_batch_completed
    • Sql_batch_starting
  • Kategori Kilidi

    • Lock_deadlock
  • Kategori Oturumu

    • Existing_connection
    • Oturum açma
    • Oturum kapatma

Yaygın engelleme senaryolarını belirleme ve çözme

Yukarıdaki bilgileri inceleyerek çoğu engelleme sorununun nedenini belirleyebilirsiniz. Bu makalenin geri kalanında, bazı yaygın engelleme senaryolarını belirlemek ve çözmek için bu bilgilerin nasıl kullanılacağı tartışılır. Bu tartışmada, engelleyici SPID'lerle ilgili bilgileri yakalamak için engelleme betiklerini (daha önce bahsedilen) kullandığınız ve XEvent oturumu kullanarak uygulama etkinliğini yakaladığınız varsayılır.

Engelleme verilerini analiz etme

  • blocking_these ve session_id kullanarak engelleme zincirlerinin başlarını belirlemek için DMV'lerin sys.dm_exec_requests ve sys.dm_exec_sessions çıkışını inceleyin. Bu, hangi isteklerin engellendiğini ve hangilerinin engellenmekte olduğunu en net şekilde belirleyecektir. Engellenen ve engellenmekte olan oturumlara daha fazla göz atın. Engelleme zincirinde ortak veya kök var mı? Büyük olasılıkla ortak bir tabloyu paylaşırlar ve engelleme zincirinde yer alan oturumlardan biri veya daha fazlası bir yazma işlemi gerçekleştiriyordur.

  • Engelleme zincirinin başındaki SPID'ler hakkında bilgi almak için DMV'lerin sys.dm_exec_requests ve sys.dm_exec_sessions çıkışını inceleyin. Aşağıdaki sütunları arayın:

    • sys.dm_exec_requests.status
      Bu sütun, belirli bir isteğin durumunu gösterir. Genellikle uyku durumu, SPID'nin yürütmeyi tamamlandığını ve uygulamanın başka bir sorgu veya toplu iş göndermesini beklediğini gösterir. Çalıştırılabilir veya çalışıyor durumu, SPID'nin şu anda bir sorguyu işlediğini gösterir. Aşağıdaki tabloda çeşitli durum değerlerinin kısa açıklamaları yer alır.

      Durum Anlamı
      Arka plan SPID kilitlenme algılama, günlük yazıcısı veya denetim noktası gibi bir arka plan görevi çalıştırıyor.
      Uyku SPID şu anda yürütmüyor. Bu genellikle SPID'nin uygulamadan bir komut beklediğini gösterir.
      Çalışıyor SPID, şu anda bir zamanlayıcıda çalışıyor.
      Çalıştırılabilir SPID, bir zamanlayıcının çalıştırılabilir kuyruğundadır ve zamanlayıcı zamanını almayı bekler.
      Askıda SPID, kilit veya mandal gibi bir kaynak bekliyor.
    • sys.dm_exec_sessions.open_transaction_count
      Bu sütun, bu oturumdaki açık işlemlerin sayısını bildirir. Bu değer 0'dan büyükse SPID açık bir işlem içindedir ve işlem içindeki herhangi bir deyim tarafından alınan kilitleri tutuyor olabilir.

    • sys.dm_exec_requests.open_transaction_count
      Benzer şekilde, bu sütun size bu istekteki açık işlemlerin sayısını bildirir. Bu değer 0'dan büyükse SPID açık bir işlem içindedir ve işlem içindeki herhangi bir deyim tarafından alınan kilitleri tutuyor olabilir.

    • sys.dm_exec_requests.wait_type, wait_time ve last_wait_type
      sys.dm_exec_requests.wait_type öğesi NULL ise istek şu anda hiçbir şey beklemiyordur ve last_wait_type değeri, isteğin karşılaştığı en son wait_type değerini gösterir. sys.dm_os_wait_stats Hakkında daha fazla bilgi ve en yaygın bekleme türlerinin açıklaması için bkz. sys.dm_os_wait_stats. wait_time değeri, isteğin ilerleme kaydedip ilerlemediğini belirlemek için kullanılabilir. sys.dm_exec_requests tablosuna karşı bir sorgu, wait_time sütununda önceki sys.dm_exec_requests sorgusundaki wait_time değerinden daha küçük bir değer döndürdüğünde bu, önceki kilidin alınıp serbest bırakıldığını ve şimdi yeni bir kilitte beklediğini gösterir (wait_time değerinin sıfır olmadığı varsayılarak). Bu, isteğin beklediği kaynağı görüntüleyen sys.dm_exec_requests çıkışı arasındaki wait_resource karşılaştırılarak doğrulanabilir.

    • sys.dm_exec_requests.wait_resource Bu sütun, engellenen bir isteğin beklediği kaynağı belirtir. Aşağıdaki tabloda yaygın wait_resource biçimleri ve anlamları listelenmiştir:

      Kaynak Biçim Örnek Açıklama
      Tablo DatabaseID:ObjectID:IndexID SEKME: 5:261575970:1 Bu durumda veritabanı kimliği 5, pubs örnek veritabanıdır ve object_id 261575970, başlık tablosudur ve 1, kümelenmiş dizindir.
      Sayfa Veritabanı Kimliği:Dosya Kimliği:Sayfa Kimliği SAYFA: 5:1:104 Bu durumda, veritabanı kimliği 5 pub, dosya kimliği 1 birincil veri dosyası ve sayfa 104 başlıklar tablosuna ait bir sayfadır. Sayfanın ait olduğu object_id'yi tanımlamak için sys.dm_db_page_info dinamik yönetim işlevini kullanarak wait_resource'den DatabaseID, FileId, PageId değerini geçirin.
      Tuş Veritabanı Kimliği:Hobt_id (Dizin anahtarı için karma değeri) ANAHTAR: 5:72057594044284928 (3300a4f361aa) Bu durumda, veritabanı kimliği 5 Pubs'tır Hobt_ID 72057594044284928 object_id 261575970 için index_id 2'ye karşılık gelir (başlıklar tablosu). sys.partitions'yi kullanarak hobt_id'i belirli bir index_id ve object_id ile ilişkilendirin. Dizin anahtarı karmasını belirli bir anahtar değeriyle değiştirmenin hiçbir yolu yoktur.
      Satır Veritabanı Kimliği:Dosya Kimliği:Sayfa Kimliği:Yuva (satır) RID: 5:1:104:3 Bu durumda, veritabanı kimliği 5 pubs, dosya kimliği 1 birincil veri dosyasıdır, sayfa 104 başlık tablosuna ait bir sayfadır ve yuva 3 satırın sayfadaki konumunu gösterir.
      Derleme Veritabanı Kimliği:Dosya Kimliği:Sayfa Kimliği:Yuva (satır) RID: 5:1:104:3 Bu durumda, veritabanı kimliği 5 pubs, dosya kimliği 1 birincil veri dosyasıdır, sayfa 104 başlık tablosuna ait bir sayfadır ve yuva 3 satırın sayfadaki konumunu gösterir.
    • sys.dm_tran_active_transactionssys.dm_tran_active_transactions DMV, işleme veya geri alma bekleyen işlemlerin tam resmi için diğer DMV'lere katılabilen açık işlemler hakkındaki verileri içerir. Sys.dm_tran_session_transactions dahil olmak üzere diğer DMV'lere katılmış açık işlemler hakkında bilgi döndürmek için aşağıdaki sorguyu kullanın. Bir işlemin geçerli durumunu, transaction_begin_time ve diğer durum verilerini göz önünde bulundurarak bir engelleme kaynağı olup olmadığını değerlendirin.

      SELECT tst.session_id, [database_name] = db_name(s.database_id)
      , tat.transaction_begin_time
      , transaction_duration_s = datediff(s, tat.transaction_begin_time, sysdatetime()) 
      , transaction_type = CASE tat.transaction_type  WHEN 1 THEN 'Read/write transaction'
                                                      WHEN 2 THEN 'Read-only transaction'
                                                      WHEN 3 THEN 'System transaction'
                                                      WHEN 4 THEN 'Distributed transaction' END
      , input_buffer = ib.event_info, tat.transaction_uow     
      , transaction_state  = CASE tat.transaction_state    
                  WHEN 0 THEN 'The transaction has not been completely initialized yet.'
                  WHEN 1 THEN 'The transaction has been initialized but has not started.'
                  WHEN 2 THEN 'The transaction is active - has not been committed or rolled back.'
                  WHEN 3 THEN 'The transaction has ended. This is used for read-only transactions.'
                  WHEN 4 THEN 'The commit process has been initiated on the distributed transaction.'
                  WHEN 5 THEN 'The transaction is in a prepared state and waiting resolution.'
                  WHEN 6 THEN 'The transaction has been committed.'
                  WHEN 7 THEN 'The transaction is being rolled back.'
                  WHEN 8 THEN 'The transaction has been rolled back.' END 
      , transaction_name = tat.name, request_status = r.status
      , tst.is_user_transaction, tst.is_local
      , session_open_transaction_count = tst.open_transaction_count  
      , s.host_name, s.program_name, s.client_interface_name, s.login_name, s.is_user_process
      FROM sys.dm_tran_active_transactions tat 
      INNER JOIN sys.dm_tran_session_transactions tst  on tat.transaction_id = tst.transaction_id
      INNER JOIN Sys.dm_exec_sessions s on s.session_id = tst.session_id 
      LEFT OUTER JOIN sys.dm_exec_requests r on r.session_id = s.session_id
      CROSS APPLY sys.dm_exec_input_buffer(s.session_id, null) AS ib;
      
    • Diğer sütunlar

      sys.dm_exec_sessions ve sys.dm_exec_request'te kalan sütunlar da sorunun kaynağı hakkında içgörü sağlayabilir. Bunların yararlılıkları, sorunun koşullarına bağlı olarak değişir. Örneğin, sorunun yalnızca belirli istemcilerden (hostname), belirli ağ kitaplıklarında (client_interface_name) gerçekleşip gerçekleşmediğini, bir SPID tarafından gönderilen son toplu işin ne zaman sys.dm_exec_sessions içinde last_request_start_time olduğunu, sys.dm_exec_requests içinde start_time ile bir isteğin ne kadar süredir çalışmakta olduğunu vb. belirleyebilirsiniz.

Yaygın engelleme senaryoları

Aşağıdaki tabloda yaygın belirtiler olası nedenleri ile eşlenmiştir.

wait_type, open_transaction_countve status sütunları sys.dm_exec_request tarafından döndürülen bilgilere başvurur; diğer sütunlar sys.dm_exec_sessions tarafından döndürülebilir. "Çözümlenir mi?" sütunu, engellemenin kendi kendine çözümlenip çözümlenmeyeceğini veya oturumun komut aracılığıyla KILL çözümlenip çözümlenmeyeceğini gösterir. Daha fazla bilgi için bkz. SONLANDIRMA (Transact-SQL).

Senaryo Wait_type Open_Tran Durum Çözülür? Diğer Belirtiler
1 Null Değil >= 0 çalıştırılabilir Evet, sorgu tamamlandığında. sys.dm_exec_sessions,reads, cpu_time ve/veya memory_usage sütunları zaman içinde artacaktır. Sorgu tamamlandığında süresi yüksek olacaktır.
2 NULL >0 uykuda Hayır, ama SPID sonlandırılabilir. Bu SPID için Genişletilmiş Olay oturumunda bir dikkat sinyali görülebilir, bu da bir sorgu zaman aşımının veya iptalinin oluştuğunu belirtir.
3 NULL >= 0 çalıştırılabilir Hayır. İstemci tüm satırları getirene veya bağlantıyı kapatana kadar çözümlenmeyecektir. SPID öldürülebilir ancak 30 saniye kadar sürebilir. open_transaction_count = 0 ise ve SPID kilitleri tutarken işlem yalıtım düzeyi varsayılan ise (READ COMMITTED), bu olası bir nedendir.
4 Değişir >= 0 çalıştırılabilir Hayır. İstemci sorguları iptal edene veya bağlantıları kapatana kadar çözümlenmeyecektir. SPID'ler öldürülebilir ancak 30 saniye kadar sürebilir. Bir engelleme zincirinin başındaki SPID için sys.dm_exec_sessions içindeki hostname sütunu, engellediği SPID'lerden biriyle aynı olacaktır.
5 NULL >0 Geri alma Evet. Bu SPID için Genişletilmiş Olaylar oturumunda bir sorgu zaman aşımı veya iptal oluştuğunu veya yalnızca bir geri alma deyiminin verildiğini belirten bir uyarı sinyali görülebilir.
6 NULL >0 uyku Sonunda. Windows NT, oturumun artık etkin olmadığını belirlediğinde bağlantı kesilir. sys.dm_exec_sessions içindeki last_request_start_time değeri, geçerli saatten çok daha erkendir.

Ayrıntılı engelleme senaryoları

Senaryo 1: Normal çalışan ve uzun yürütme süresine sahip bir sorgudan kaynaklanan engelleme

Bu senaryoda, etkin bir şekilde çalışan bir sorgu kilit alır ve kilitler serbest bırakılmaz (işlem yalıtım düzeyinden etkilenir). Bu nedenle, diğer oturumlar serbest bırakılana kadar kilitlerde bekler.

Çözüm:

Bu engelleme sorununun çözümü, sorguyu en iyi duruma getirmenin yollarını aramaktır. Bu engelleme sorunu sınıfı bir performans sorunu olabilir ve bu şekilde ele almanızı gerektirir. Belirli bir yavaş çalışan sorguyla ilgili sorunları giderme hakkında bilgi için bkz. SQL Server'da yavaş çalışan sorgularda sorun giderme. Daha fazla bilgi için bkz. Performans için Görüntüleme Ayar.

Sorgu Deposu'ndan (SQL Server 2016'da kullanıma sunulan) SSMS'de yerleşik raporlar da en yüksek maliyetli sorguları, yetersiz yürütme planlarını tanımlamak için önerilen ve değerli bir araçtır.

Diğer kullanıcıları engelleyen ve iyileştirilemeyen uzun süre çalışan bir sorgunuz varsa bunu OLTP ortamından ayrılmış bir raporlama sistemine taşımayı düşünün. Veritabanının salt okunur çoğaltmasını eşitlemek için Always On kullanılabilirlik gruplarını da kullanabilirsiniz.

Not

Sorgu yürütme sırasında engellemeye, satır veya sayfa kilitlerinin tablo kilitlerine ilerletilmesine neden olan sorgu yükseltmesi neden olabilir. Microsoft SQL Server, kilit yükseltme işleminin ne zaman gerçekleştirileceğini dinamik olarak belirler. Kilit yükseltmesini önlemenin en basit ve en güvenli yolu, işlemleri kısa tutmak ve kilit yükseltme eşiklerini aşmamak için pahalı sorguların kilit ayak izini azaltmaktır. Aşırı kilit yükseltmesini algılama ve önleme hakkında daha fazla bilgi için bkz. Kilit yükseltmenin neden olduğu engelleme sorununu çözme.

Senaryo 2: Kaydedilmemiş bir işleme sahip uyuyan bir SPID'nin neden olduğu engelleme

Bu engelleme türü genellikle uykuda olan veya komut bekleyen ve işlem iç içe geçme düzeyi (sys.dm_exec_requests işleminden @@TRANCOUNT, open_transaction_count) sıfırdan büyük olan bir SPID ile tanımlanabilir. Bu durum, uygulama bir sorgu zaman aşımıyla karşılaşırsa veya gerekli sayıda ROLLBACK ve/veya COMMIT ekstresi vermeden bir iptal verirse oluşabilir. Bir SPID sorgu zaman aşımı veya iptal aldığında, geçerli sorguyu ve toplu işlemi sonlandırır ancak işlemi otomatik olarak geri almaz veya işlemez. SQL Server, tek bir sorgu iptal edildiği için işlemin tamamının geri alınması gerektiğini varsayamadığından, bunun sorumlusu uygulamadır. Sorgu zaman aşımı veya iptal, Genişletilmiş Olay oturumunda SPID için bir UYARI sinyal olayı olarak görünür.

İşlenmemiş açık bir işlemi göstermek için aşağıdaki sorguyu çalıştırın:

CREATE TABLE #test (col1 INT);
INSERT INTO #test SELECT 1;
GO
BEGIN TRAN
UPDATE #test SET col1 = 2 where col1 = 1;

Ardından bu sorguyu aynı pencerede yürütün:

SELECT @@TRANCOUNT;
ROLLBACK TRAN
DROP TABLE #test;

İkinci sorgunun çıkışı, işlem iç içe geçirme düzeyinin bir olduğunu gösterir. İşlemde alınan tüm kilitler, işlem işlenene veya geri alınana kadar tutulur. Uygulamalar işlemleri açıkça açar ve işlerse bir iletişim hatası veya başka bir hata oturumu ve işlemini açık durumda bırakabilir.

Örnek genelinde şu anda işlenmemiş işlemleri belirlemek için bu makalenin sys.dm_tran_active_transactions temelli önceki bölümlerindeki betiği kullanın.

Çözümler:

  • Ayrıca, bu engelleme sorunu sınıfı da bir performans sorunu olabilir ve bu nedenle bunu takip etmenizi gerektirir. Sorgu yürütme süresi azaltılabilirse sorgu zaman aşımı veya iptal gerçekleşmez. Uygulamanın, ortaya çıkması durumunda zaman aşımı veya iptal senaryolarını ele alabilmesi önemlidir ancak sorgunun performansını inceleme avantajından da yararlanabilirsiniz.

  • Uygulamalar, işlem iç içe yerleştirme düzeylerini düzgün bir şekilde yönetmelidir yoksa sorgunun bu şekilde iptal edilmesinden sonra engelleme sorununa neden olabilir. Şunları göz önünde bulundurun:

    • İstemci uygulaması bir işlemin açık olduğuna inanmasa bile istemci uygulamasının hata işleyicisinde herhangi bir hatanın sonrasında IF @@TRANCOUNT > 0 ROLLBACK TRAN komutunu yürütün. Toplu işlem sırasında bir saklı yordam çağırdığından, istemci uygulamanın bilgisi olmadan bir işlem başlatmış olabileceğinden, açık işlemlerin denetlenmesi gerekir. Sorguyu iptal etme gibi belirli koşullar, yordamın geçerli deyimi geçmişe atmasını önler bu nedenle yordamın, IF @@ERROR <> 0 işlemini denetleme ve işlemi durdurma mantığı olsa bile, bu geri alma kodu bu gibi durumlarda yürütülmeyecektir.

    • Bağlantı havuzu, web tabanlı bir uygulama gibi bağlantıyı açan ve yeniden havuza bağlanmadan önce birkaç sorgu çalıştıran bir uygulamada kullanılıyorsa bağlantı havuzunun geçici olarak devre dışı bırakılması, istemci uygulaması hataları uygun şekilde işlemek üzere değiştirilene kadar sorunun hafifletilmesine yardımcı olabilir. Bağlantı havuzunu devre dışı bırakarak bağlantının serbest bırakılması, SQL Server bağlantısının fiziksel olarak kesilmesine neden olur ve bu da sunucunun açık işlemleri geri döndürmesine neden olur.

    • Bağlantı için veya işlemleri başlatan ve bir hatadan sonra temizlemeyen saklı yordamlarda SET XACT_ABORT ON kullanın. Çalışma zamanı hatası durumunda bu ayar, tüm açık işlemleri durdurur ve denetimi istemciye döndürür. Daha fazla bilgi için SET XACT_ABORT (Transact-SQL) bölümünü gözden geçirin.

Not

Bağlantı havuzundan yeniden kullanılana kadar bağlantı sıfırlanmaz, bu nedenle bir kullanıcının bir işlemi açıp bağlantı havuzuna bağlantıyı serbest bırakması mümkündür ancak işlem açık kalırken birkaç saniye boyunca yeniden kullanılamayabilir. Bağlantı yeniden kullanılmazsa bağlantı zaman aşımına uğradığında ve bağlantı havuzundan kaldırıldığında işlem durdurulacaktır. Bu nedenle, istemci uygulamasının hata işleyicisindeki işlemleri durdurması veya bu olası gecikmeyi önlemek için SET XACT_ABORT ON kullanması idealdir.

Dikkat

SET XACT_ABORT ON işlemini takiben, hataya neden olan bir deyimi izleyen T-SQL deyimleri yürütülmeyecektir. Bu, mevcut kodun hedeflenen akışını etkileyebilir.

Senaryo 3: İlgili istemci uygulamasının tüm sonuç satırlarını tamamlamamış olduğu bir SPID'nin neden olduğu engelleme

Sunucuya bir sorgu gönderdikten sonra, tüm uygulamaların hemen tüm sonuç satırlarını tamamlaması gerekir. Bir uygulama tüm sonuç satırlarını getirmezse kilitler tablolarda bırakılabilir ve diğer kullanıcıları engelleyebilir. SQL deyimlerini sunucuya şeffaf bir şekilde gönderen bir uygulama kullanıyorsanız uygulamanın tüm sonuç satırlarını getirmesi gerekir. Yapmıyorsa (ve bunu yapacak şekilde yapılandırılamıyorsa) engelleme sorununu çözemeyebilirsiniz. Sorundan kaçınmak için kötü davranış sergileyen uygulamaları, ana OLTP veritabanından ayrı bir raporlama veya karar destek veritabanıyla kısıtlayabilirsiniz.

Çözüm:

Sonucun tüm satırlarını tamamlayacak şekilde uygulamanın yeniden yazılması gerekir. Bu, sunucu tarafı sayfalamasını gerçekleştirmek için sorgunun ORDER BY yan tümcesinde OFFSET ve FETCH kullanımını dışlamaz.

Senaryo 4: Dağıtılmış istemci/sunucu kilitlenmesi nedeniyle engelleme

Geleneksel bir kilitlenmeden farklı olarak dağıtılmış bir kilitlenme, RDBMS kilit yöneticisi kullanılarak algılanamaz. Bunun nedeni, kilitlenmeye dahil olan kaynaklardan yalnızca birinin SQL Server kilidi olmasıdır. Kilitlenmenin diğer tarafı istemci uygulama düzeyindedir ve üzerinde SQL Server denetimi yoktur. Bunun nasıl gerçekleşebileceğini ve uygulamanın bunu önlemesinin olası yollarını gösteren iki örnek aşağıda verilmiştir.

Örnek A: Tek bir istemci iş parçacığı ile istemci/sunucu dağıtılmış kilitlenmesi

İstemcinin birden çok açık bağlantısı ve tek bir yürütme iş parçacığı varsa aşağıdaki dağıtılmış kilitlenme oluşabilir. Kısa olması için burada kullanılan dbproc teriminin, istemci bağlantı yapısını ifade ettiğine dikkat edin.

 SPID1------blocked on lock------->SPID2
   /\ (waiting to write results back to client)
   | 
   | |
   | | Server side
   | ================================|==================================
   | <-- single thread --> | Client side
   | \/
   dbproc1 <------------------- dbproc2
   (waiting to fetch (effectively blocked on dbproc1, awaiting
   next row) single thread of execution to run)

Yukarıda gösterilen örnekte, tek bir istemci uygulama iş parçacığının iki açık bağlantısı vardır. Dbproc1 üzerinde asenkron bir SQL işlemi gönderir. Bu, devam etmeden önce geri dönmek için aramayı beklemediği anlamına gelir. Uygulama daha sonra dbproc2 üzerinde başka bir SQL işlemi gönderir ve döndürülen verileri işlemeye başlamak için sonuçları bekler. Veriler geri gelmeye başladığında (hangi dbproc önce yanıt verirse--bunun dbproc1 olduğunu varsayalım), bu dbproc üzerinde döndürülen tüm verileri tamamlayarak işler. SPID1, SPID2 tarafından tutulan bir kilitte engellenene kadar dbproc1'den sonuçları getirir (çünkü iki sorgu sunucuda asenkron olarak çalışır). Bu noktada, dbproc1 daha fazla veri için süresiz olarak bekler. SPID2 bir kilit üzerinde engellenmez ancak istemcisi olan dbproc2'ye veri göndermeye çalışır. Ancak, uygulama için tek yürütme iş parçacığı dbproc1 tarafından kullanıldığı için dbproc2, uygulama katmanında dbproc1 üzerinde etkin bir şekilde engellenir. Bu, ilgili kaynaklardan yalnızca biri SQL Server kaynağı olduğundan, SQL Server'ın algılayamadığı veya çözümleyemediği bir kilitlenmeyle sonuçlanır.

Örnek B: Bağlantı başına bir iş parçacığı ile istemci/sunucu dağıtılmış kilitlenmesi

İstemcideki her bağlantı için ayrı bir iş parçacığı bulunsa bile, yine de aşağıda gösterildiği şekilde, bu dağıtılmış kilitlenmenin bir varyasyonu oluşabilir.

SPID1------blocked on lock-------->SPID2
  /\ (waiting on net write) Server side
  | |
  | |
  | INSERT |SELECT
  | ================================|==================================
  | <-- thread per dbproc --> | Client side
  | \/
  dbproc1 <-----data row------- dbproc2
  (waiting on (blocked on dbproc1, waiting for it
  insert) to read the row from its buffer)

Bu durum Örnek A'ya benzer, ancak dbproc2 ve SPID2 aynı tablodaki bir INSERT, UPDATEveya DELETE deyimi için her defasında bir satır işleme gerçekleştirmek ve her satırı bir arabellek aracılığıyla dbproc1'e teslim etmek amacıyla bir SELECT deyimini çalıştırır. Sonunda, (INSERT, UPDATE veya DELETE'ü gerçekleştiren) SPID1, (SELECT'i gerçekleştiren) SPID2 tarafından tutulan bir kilit üzerinde engellenir. SPID2, istemci dbproc2'ye bir sonuç satırı yazar. Daha sonra, dbproc2 bir arabellekteki satırı dbproc1'e geçirmeye çalışır, ancak dbproc1'in meşgul olduğunu tespit eder (SPID2'de engellenen geçerli INSERT öğesini bitirmek için SPID1'de beklerken engellenir). Bu noktada dbproc2, SPID'si (SPID1) SPID2 tarafından veritabanı düzeyinde engellenen dbproc1 tarafından uygulama katmanında engellenir. Bu da ilgili kaynaklardan yalnızca biri SQL Server kaynağı olduğundan yine SQL Server'ın algılayamadığı veya çözemediği bir kilitlenmeyle sonuçlanır.

Hem A hem de B örneği, uygulama geliştiricilerinin farkında olması gereken temel sorunlardır. Uygulamaları bu durumları uygun bir şekilde ele alacak şekilde kodlamaları gerekir.

Çözüm:

Bir sorgu zaman aşımı belirtildiğinde, dağıtılmış kilitlenme oluşursa, zaman aşımı gerçekleştiğinde bozulur. Sorgu zaman aşımı kullanma hakkında daha fazla bilgi için bağlantı sağlayıcısı belgelerinize başvurun.

Senaryo 5: Geri alma durumundaki bir oturumun neden olduğu engelleme

Sonlandırılmış olan veya kullanıcı tanımlı işlem dışında iptal edilen bir veri değişikliği sorgusu geri alınır. Bu durum istemci ağ oturumunun bağlantısının kesilmesinin bir yan etkisi olarak veya bir istek kilitlenme kurbanı olarak seçildiğinde de oluşabilir. Bu genellikle GERİ ALMA command öğesini gösterebilen sys.dm_exec_requests çıkışını gözlemleyerek tanımlanabilir ve percent_complete sütunu ilerleme durumunu gösterebilir.

Sonlandırılmış olan veya kullanıcı tanımlı işlem dışında iptal edilen bir veri değişikliği sorgusu geri alınır. Bu durum, istemci bilgisayarın yeniden başlatılmasının ve ağ oturumunun bağlantısının kesilmesinin bir yan etkisi olarak da oluşabilir. Benzer şekilde, kilitlenme kurbanı olarak seçilen sorgu geri alınır. Veri değişikliği sorgusu genellikle değişikliklerin ilk uygulandığından daha hızlı geri alınamaz. Örneğin, bir DELETE, INSERTveya UPDATE deyimi bir saattir çalışıyorsa geri alınması en az bir saat sürebilir. Yapılan değişikliklerin geri alınması gerektiğinden veya veritabanındaki işlem tabanlı ve fiziksel bütünlük tehlikeye atılacağından bu beklenen bir davranıştır. Böyle olması gerektiğinden, SQL Server SPID'yi altın veya geri alma durumunda işaretler (bu da sonlandırılamayacağı veya kilitlenme kurbanı olarak seçilemeyeceği anlamına gelir). Bu genellikle, Geri Al komutunu gösterebilecek sp_who çıkışı gözlemlenerek tanımlanabilir. sys.dm_exec_sessions'ün status sütunu, Geri Alma durumunu gösterir.

Not

Hızlandırılmış Veritabanı Kurtarma özelliği etkinleştirildiğinde uzun süren geri alma işlemleri nadirdir. Bu özellik, SQL Server 2019'da kullanılmaya başlanmıştır.

Çözüm:

Oturumun yapılan değişiklikleri geri alma işlemini bitirmesini beklemeniz gerekir.

Örnek bu işlemin ortasında kapatılırsa, yeniden başlatıldıktan sonra veritabanı kurtarma moduna geçer ve tüm açık işlemler işlenene kadar erişilmez olur. Başlangıç kurtarma işlemi, her işlem için çalışma zamanı kurtarma işlemiyle aynı süreyi alır ve bu süre boyunca veritabanına erişilemez. Bu nedenle, sunucuyu geri alma durumundaki bir SPID'yi düzeltmek için zorlamak genellikle verimsizdir. Hızlandırılmış Veritabanı Kurtarma etkinleştirilmiş olan SQL Server 2019'da bu durum oluşmaz.

Bu durumu önlemek için OLTP sistemlerinde yoğun saatlerde büyük toplu yazma işlemleri veya dizin oluşturma veya bakım işlemleri gerçekleştirmeyin. Mümkünse, bu tür işlemleri düşük etkinlikli dönemlerde gerçekleştirin.

Senaryo 6: Yalnız bırakılmış bir işlemin neden olduğu engelleme

Bu yaygın bir sorun senaryosudur ve kısmen Senaryo 2 ile çakışır. İstemci uygulaması durursa, istemci iş istasyonu yeniden başlatılırsa veya toplu iptal hatası oluşursa bunların tümü işlemi açık bırakabilir. Bu durum, uygulamanın CATCH veya FINALLY bloklarındaki işlemi geri almazsa veya bu durumu başka bir şekilde işlemezse ortaya çıkabilir.

Bu senaryoda, bir SQL toplu işleminin yürütülmesi iptal edilirken, uygulama SQL bağlantısını ve işlemini açık bırakır. SQL Server örneğinin perspektifinden bakıldığında istemci hala mevcut gibi görünür ve alınan tüm kilitler hala tutulur.

Yalnız bırakılmış bir işlemi göstermek için, var olmayan bir tabloya veri ekleyerek toplu iptal hatasının benzetimini yapan aşağıdaki sorguyu yürütün:

CREATE TABLE #test2 (col1 INT);
INSERT INTO #test2 SELECT 1;
go
BEGIN TRAN
UPDATE #test2 SET col1 = 2 where col1 = 1;
INSERT INTO #NonExistentTable values (10)

Ardından bu sorguyu aynı pencerede yürütün:

SELECT @@TRANCOUNT;

İkinci sorgunun çıkışı, işlem iç içe geçirme düzeyinin bir olduğunu gösterir. İşlemde alınan tüm kilitler, işlem işlenene veya geri alınana kadar tutulur. Toplu iş sorgu tarafından zaten durdurulmuş olduğundan, yürüten uygulama hala açık olan işlemi temizlemeden aynı oturumda diğer sorguları çalıştırmaya devam edebilir. Oturum kapatılana veya SQL Server örneği yeniden başlatılana kadar kilit tutulur.

Çözümler:

  • Bu durumu önlemenin en iyi yolu, özellikle beklenmeyen sonlandırmalar için uygulama hata/özel durum işlemesini iyileştirmektir. Uygulama kodunda bir Try-Catch-Finally bloğu kullandığınızdan emin olun ve bir özel durum söz konusu olduğunda işlemi geri alın.
  • Oturum için veya işlemleri başlatan ve bir hatadan sonra temizlemeyen saklı yordamlarda SET XACT_ABORT ON kullanın. Toplu işi iptal eden bir çalışma zamanı hatası durumunda bu ayar, tüm açık işlemleri otomatik olarak geri alır ve denetimi istemciye döndürür. Daha fazla bilgi için SET XACT_ABORT (Transact-SQL) bölümünü gözden geçirin.
  • Kaynaklarını düzgün bir şekilde temizlemeden bağlantısı kesilmiş bir istemci uygulamasının yalnız bırakılmış bağlantısını çözümlemek için KILL komutunu kullanarak SPID'yi sonlandırabilirsiniz. Başvuru için bkz. KILL (Transact-SQL).

KILL komutu, SPID değerini giriş olarak alır. Örneğin, SPID 9'u sonlandırmak için aşağıdaki komutu çalıştırın:

KILL 99

Not

KILL komutunun tamamlanması, KILL komutunun denetimleri arasındaki aralık nedeniyle 30 saniye kadar sürebilir.

Ayrıca bkz.