Aracılığıyla paylaş


SQL Server'da sürekli çalışıyor gibi görünen sorgularda sorun giderme

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, FAST veya EXISTS kullanı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.
  • 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
  • running veya runnable durumu
  • 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 Management Studio (SSMS) kullanarak tanılama verilerini toplamak için şu adımları izleyin:

  1. Tahmini sorgu yürütme planı XML'sini yakalayın.

  2. 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
    • SELECT Listedeki her satırın işlenmesi uzun süren işlevler
  3. 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:

  1. Daha önce kaydedilmiş bir sorgu yürütme planı dosyasını (.sqlplan açın.

  2. Yürütme planının boş bir alanına sağ tıklayın ve Showplan'ı Karşılaştır'ı seçin.

  3. Karşılaştırmak istediğiniz ikinci sorgu planı dosyasını seçin.

  4. İş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.

  5. 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:

    SSMS'de sorgu planlarını karşılaştırmayı gösteren ekran görüntüsü.

4. Adım: Çözüm

  1. Sorguda kullanılan tablolar için istatistiklerin güncelleştirildiğinden emin olun.

  2. Sorgu planında eksik dizin önerilerini arayın ve bulduklarını uygulayın.

  3. Sorguyu basitleştirin:

    • Önceden işlenen verileri azaltmak için daha seçmeli WHERE koşul kullanın.
    • Parçala.
    • Geçici tablolarda bazı bölümleri seçin ve daha sonra birleştirin.
    • TOP, EXISTS, ve FAST (T-SQL) öğelerini, bir optimizasyon satır hedefi nedeniyle uzun süre çalışan sorgulardan kaldırın.
    • Deyimleri tek bir büyük sorguda birleştirdiklerinden, bu gibi durumlarda Ortak Tablo İfadelerini (CTE) kullanmaktan kaçının.
  4. Daha iyi bir plan oluşturmak için sorgu ipuçlarını kullanmayı deneyin:

    • HASH JOIN veya MERGE JOIN ipucu
    • FORCE ORDER ima
    • FORCESEEK ima
    • RECOMPILE
    • KULLANIN PLAN N'<xml_plan>' (zorlayabileceğiniz hızlı bir sorgu planınız varsa)
  5. 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.