Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu makalede, Bir Microsoft SQL Server sorgusunun sona ermesi çok uzun sürdüğü (saatler veya günler) sorunlar için sorun giderme kılavuzu sağlanır.
Belirti -leri
Bu makale, bitmeden çalıştırılacak veya derlenmiş gibi görünen sorgulara odaklanmaktadır. Yani CPU kullanımı artmaya devam eder. Bu makale, engellenen veya hiç yayımlanmamış bir kaynağı bekleyen sorgular için geçerli değildir. Bu gibi durumlarda CPU kullanımı sabit kalır veya yalnızca biraz değişir.
Önemli
Bir sorgu çalışmaya devam etmek üzere bırakılırsa, sonunda bitebilir. Bu işlem yalnızca birkaç saniye veya birkaç gün sürebilir. Bazı durumlarda sorgu gerçekten sonsuz olabilir, örneğin bir WHILE döngüsünden çıkılmadığında. "Hiç bitmeyen" terimi burada bitmeyen bir sorgunun algısını açıklamak için kullanılır.
Nedeni
Uzun süre çalışan (hiç bitmeyen) sorguların yaygın nedenleri şunlardır:
-
İç İçe Döngü (NL) çok büyük tablolarda birleşir: NL birleşimlerinin doğası gereği, çok sayıda satırı olan tabloları birleştiren bir sorgu uzun süre çalıştırılabilir. Daha fazla bilgi için Birleştirmeler bölümüne bakın.
- NL birleştirmesinin bir örneği,
TOP,FASTveyaEXISTSkullanımıdır. Hash veya Birleştirme birleştirmesi daha hızlı olsa bile, iyileştirici satır hedefi nedeniyle her iki operatörü de kullanamaz. - NL birleştirmenin bir diğer örneği de sorguda eşitsizlik içeren birleştirme koşulunun kullanılmasıdır. Örneğin,
SELECT .. FROM tab1 AS a JOIN tab 2 AS b ON a.id > b.id. İyileştirici burada Merge veya Hash joinleri de kullanamaz.
- NL birleştirmesinin bir örneği,
- Güncel olmayan istatistikler: Güncel olmayan istatistiklere dayalı bir plan seçen sorgular yetersiz olabilir ve çalıştırılması uzun sürebilir.
- Sonsuz döngüler: WHILE döngülerini kullanan T-SQL sorguları yanlış yazılmış olabilir. Sonuçta elde edilen kod hiçbir zaman döngüden ayrılmaz ve sonsuz bir şekilde çalışır. Bu sorgular gerçekten hiç bitmeyen sorgulardır. El ile ölene kadar koşuyorlar.
- Çok sayıda birleştirme ve büyük tablo içeren karmaşık sorgular: Birçok birleştirilmiş tablo içeren sorguların çalışması genellikle uzun sürebilecek karmaşık sorgu planlarına sahip olur. Bu senaryo, satırları filtrelemeyen ve çok sayıda tablo içeren analitik sorgularda yaygındır.
- Eksik dizinler: Tablolarda uygun dizinler kullanılıyorsa sorgular önemli ölçüde daha hızlı çalıştırılabilir. Dizinler, daha hızlı erişim sağlamak için verilerin bir alt kümesinin seçilmesini sağlar.
Çözüm
1. Adım: Hiç bitmeyen sorguları bulma
Sistemde çalışan hiç bitmeyen bir sorgu arayın. Sorguda uzun bir yürütme süresi, uzun bir bekleme süresi (dar boğaza takılmış) veya uzun bir derleme süresi olup olmadığını tespit etmelisiniz.
1.1 Tanılama çalıştırma
Hiç bitmeyen sorgunun etkin olduğu SQL Server örneğinizde aşağıdaki tanılama sorgusunu çalıştırın:
DECLARE @cntr INT = 0
WHILE (@cntr < 3)
BEGIN
SELECT TOP 10 s.session_id,
r.status,
CAST(r.cpu_time / (1000 * 60.0) AS DECIMAL(10,2)) AS cpu_time_minutes,
CAST(r.total_elapsed_time / (1000 * 60.0) AS DECIMAL(10,2)) AS elapsed_minutes,
r.logical_reads,
r.wait_time,
r.wait_type,
r.wait_resource,
r.reads,
r.writes,
SUBSTRING(st.TEXT, (r.statement_start_offset / 2) + 1,
((CASE r.statement_end_offset
WHEN -1 THEN DATALENGTH(st.TEXT)
ELSE r.statement_end_offset
END - r.statement_start_offset) / 2) + 1) AS statement_text,
COALESCE(QUOTENAME(DB_NAME(st.dbid)) + N'.' + QUOTENAME(OBJECT_SCHEMA_NAME(st.objectid, st.dbid))
+ N'.' + QUOTENAME(OBJECT_NAME(st.objectid, st.dbid)), '') AS command_text,
r.command,
s.login_name,
s.host_name,
s.program_name,
s.last_request_end_time,
s.login_time,
r.open_transaction_count,
atrn.name as transaction_name,
atrn.transaction_id,
atrn.transaction_state
FROM sys.dm_exec_sessions AS s
JOIN sys.dm_exec_requests AS r ON r.session_id = s.session_id
CROSS APPLY sys.Dm_exec_sql_text(r.sql_handle) AS st
LEFT JOIN (sys.dm_tran_session_transactions AS stran
JOIN sys.dm_tran_active_transactions AS atrn
ON stran.transaction_id = atrn.transaction_id)
ON stran.session_id =s.session_id
WHERE r.session_id != @@SPID
ORDER BY r.cpu_time DESC
SET @cntr = @cntr + 1
WAITFOR DELAY '00:00:05'
END
1.2 Çıktıyı inceleme
Bir sorguyu uzun süre çalıştırmaya neden olabilecek çeşitli senaryolar vardır: uzun yürütme, uzun bekleme ve uzun derleme. Sorgunun neden yavaş çalışabileceği hakkında daha fazla bilgi için bkz: Çalışıyor ve Bekliyor: Sorgular neden yavaş?
Uzun işlem süresi
Bu makaledeki sorun giderme adımları, AŞAĞıDAKIne benzer bir çıkış aldığınızda geçerlidir; burada CPU süresi, önemli bekleme süreleri olmadan geçen süreyle orantılı olarak artar.
| session_id | durum | işlemci_zaman_dakika | geçen_zaman_dakika | logical_reads | bekleme_süresi_dakika | wait_type |
|---|---|---|---|---|---|---|
| 56 | çalışıyor | 64.40 | 23.50 | 0 | 0.00 | NULL |
Aşağıdakiler varsa sorgu sürekli olarak çalışır:
- Artan CPU süresi
-
runningveyarunnabledurumu - Minimum veya sıfır bekleme süresi
- Herhangi bir wait_type yok
Bu durumda sorgu satırları okumak, birleştirmek, sonuçları işlemek, hesaplamak veya biçimlendirmektir. Bu etkinliklerin tümü CPU'ya bağlı eylemlerdir.
Not
logical_reads içindeki değişiklikler, hesaplamalar veya WHILE döngü gerçekleştirme gibi bazı CPU'ya bağlı T-SQL isteklerinin hiç mantıksal okuma yapmayabileceği için bu durumda alakalı değildir.
Yavaş sorgu bu ölçütleri karşılıyorsa çalışma zamanını azaltmaya odaklanın. Çalışma zamanının azaltılması genellikle dizinleri uygulayarak, sorguyu yeniden yazarak veya istatistikleri güncelleştirerek sorgunun ömrü boyunca işlemesi gereken satır sayısını azaltmayı içerir. Daha fazla bilgi için Çözüm bölümüne bakın.
Uzun bekleme süresi
Bu makale uzun bekleme senaryoları için geçerli değildir. Bekleme senaryosunda, oturum bir kaynağı beklediği için CPU kullanımının değişmediği ya da çok az değişiklik gösterdiği aşağıdaki örnekle benzer bir çıkış alabilirsiniz:
| session_id | durum | işlemci_zaman_dakika | geçen_zaman_dakika | logical_reads | bekleme_süresi_dakika | wait_type |
|---|---|---|---|---|---|---|
| 56 | Askıya | 0.03 | 4.20 | 50 | 4.10 | LCK_M_U |
Bekleme türü, oturumun bir kaynağı beklediğini gösterir. Uzun geçen bir süre ve uzun bir bekleme süresi, oturumun yaşam süresinin büyük bölümünü bu kaynağı bekleyerek geçirdiğini gösterir. Kısa CPU süresi, sorguyu işlemek için çok az zaman harcandığını gösterir.
Beklemeler nedeniyle uzun süren sorguların sorunlarını gidermek için bkz. SQL Server'da yavaş çalışan sorgularla ilgili sorunları giderme.
Uzun derleme süresi
Nadiren, CPU kullanımının zaman içinde sürekli arttığını ancak bunun sorgu yürütme tarafından yönlendirilmediğini gözlemleyebilirsiniz. Bunun yerine, aşırı uzun derleme (sorguyu ayrıştırma ve derleme) bunun nedeni olabilir. Bu gibi durumlarda çıkış sütununu transaction_name değerinin sqlsource_transformolup olmadığını denetleyin. Bu işlem adı bir derlemeyi gösterir.
2. Adım: Tanılama günlüklerini el ile toplama
Sistemde hiç bitmeyen bir sorgu olduğunu belirledikten sonra, daha fazla sorun gidermek için sorgunun plan verilerini toplayabilirsiniz. Verileri toplamak için SQL Server sürümünüze bağlı olarak aşağıdaki yöntemlerden birini kullanın.
- SQL Server 2008 - SQL Server 2014 (SP2'den önceki)
- SQL Server 2014 (SP2'den sonraki) ve SQL Server 2016 (SP1'den önceki)
- SQL Server 2016 (SP1'den sonraki) ve SQL Server 2017
- SQL Server 2019 ve sonraki sürümleri
SQL Server Management Studio (SSMS) kullanarak tanılama verilerini toplamak için şu adımları izleyin:
Tahmini sorgu yürütme planı XML'sini yakalayın.
Verilerin yavaşlığa neyin neden olduğuna ilişkin belirgin göstergeler gösterip göstermeyeceğini öğrenmek için sorgu planını gözden geçirin. Tipik endikasyonlara örnek olarak şunlar verilebilir:
- Tablo veya dizin taramaları (tahmini satırlara bakın)
- Büyük bir dış tablo veri kümesi tarafından yönetilen iç içe döngüler
- Döngünün iç tarafında büyük bir dala sahip iç içe döngüler
- Tablo biriktiricileri
-
SELECTListedeki her satırın işlenmesi uzun süren işlevler
Sorgu istediğiniz zaman daha hızlı çalışıyorsa, sonuçları karşılaştırmak için "hızlı" çalıştırmaları (gerçek XML yürütme planı) yakalayabilirsiniz.
Sql LogScout kullanarak hiç bitmeyen sorguları yakalama
Hiç bitmeyen bir sorgu çalışırken günlükleri yakalamak için SQL LogScout kullanabilirsiniz. Aşağıdaki komutla hiç bitmeyen sorgu senaryosunu kullanın:
.\SQL_LogScout.ps1 -Scenario "NeverEndingQuery" -ServerName "SQLInstance"
Not
Bu günlük yakalama işlemi, uzun sorgunun en az 60 saniye CPU süresi tüketmesini gerektirir.
SQL LogScout, her yüksek CPU kullanan sorgu için en az üç sorgu planı yakalar. benzer servername_datetime_NeverEnding_statistics_QueryPlansXml_Startup_sessionId_#.sqlplandosya adlarını bulabilirsiniz. Uzun sorgu yürütme nedenini belirlemek için planları gözden geçirirken sonraki adımda bu dosyaları kullanabilirsiniz.
3. Adım: Toplanan planları gözden geçirme
Bu bölümde, toplanan verilerin nasıl gözden geçirılacağı açıklanır. Microsoft SQL Server 2016 SP1 ve sonraki derlemelerde ve sürümlerde toplanan birden çok XML sorgu planını (uzantı .sqlplankullanarak) kullanır.
Aşağıdaki adımları izleyerek yürütme planlarını karşılaştırın:
Daha önce kaydedilmiş bir sorgu yürütme planı dosyasını (
.sqlplanaçın.Yürütme planının boş bir alanına sağ tıklayın ve Showplan'ı Karşılaştır'ı seçin.
Karşılaştırmak istediğiniz ikinci sorgu planı dosyasını seçin.
İşleçler arasında akan çok sayıda satırı gösteren kalın okları arayın. Ardından, ok öncesinde veya sonrasında işleci seçin ve iki plandaki gerçek satır sayısını karşılaştırın.
En büyük satır akışının aynı işleçlerde olup olmadığını öğrenmek için ikinci ve üçüncü planları karşılaştırın.
Örneğin:
4. Adım: Çözüm
Sorguda kullanılan tablolar için istatistiklerin güncelleştirildiğinden emin olun.
Sorgu planında eksik dizin önerilerini arayın ve bulduklarını uygulayın.
Sorguyu basitleştirin:
- Önceden işlenen verileri azaltmak için daha seçmeli
WHEREkoşul kullanın. - Parçala.
- Geçici tablolarda bazı bölümleri seçin ve daha sonra birleştirin.
-
TOP,EXISTS, veFAST(T-SQL) öğelerini, bir optimizasyon satır hedefi nedeniyle uzun süre çalışan sorgulardan kaldırın.- Alternatif olarak
DISABLE_OPTIMIZER_ROWGOALkullanın. Daha fazla bilgi için bkz . Row Goals Gone Rogue.
- Alternatif olarak
- Deyimleri tek bir büyük sorguda birleştirdiklerinden, bu gibi durumlarda Ortak Tablo İfadelerini (CTE) kullanmaktan kaçının.
- Önceden işlenen verileri azaltmak için daha seçmeli
Daha iyi bir plan oluşturmak için sorgu ipuçlarını kullanmayı deneyin:
-
HASH JOINveyaMERGE JOINipucu -
FORCE ORDERima -
FORCESEEKima RECOMPILE- KULLANIN
PLAN N'<xml_plan>'(zorlayabileceğiniz hızlı bir sorgu planınız varsa)
-
Böyle bir plan varsa ve SQL Server sürümünüz Sorgu Deposu'nu destekliyorsa, iyi bilinen bir planı zorlamak için Sorgu Deposu'nu (QDS) kullanın.