SQL Server 2008 R2'de SQL Server deyimleri zaman zaman yavaşlıyor


13

Müşterilerimizden birinde, uygulamamızda bazı performans sorunları yaşıyoruz. Bir SQL Server veritabanındaki verileri tüketen ve güncelleyen bir .NET 3.5 web uygulamasıdır. Üretim ortamımız şu anda ön uç olarak bir Windows 2008 R2 makinesinden ve arka uçta bir SQL Server 2008 R2 kümesinden oluşuyor. Bizim app veritabanına bağlanmak için COM + ve MSDTC kullanır.

İşte olanlar: Son kullanıcılarımız bazen uygulamadaki yavaşlıktan şikayet ediyorlar. Bazı sayfaların yüklenmesi beklenenden daha fazla zaman alıyor. Ne olduğunu anlamaya çalışırken, veritabanı tarafında performans düşüşünün nedeni olabilecek bazı garip davranışlar bulmayı başardım. Bazen ne olacağını çalıştırmak için çok daha fazla zaman alan bazı SQL ifadeleri olduğunu fark ettim. Uzun süren sorguları tanımlamak için bir profiler izlemesi (TSQL_Duration şablonu ile) kullanarak bu ifadelerden bazılarını (esas olarak uygulamanın saklı yordamlarının çağrıları) tanımlamayı başardım.

Sorun bu saklı yordamlar doğrudan SQL Management Studio üzerinde veritabanında çalıştırdığınızda bazen uzun (yaklaşık 7/8 saniye), diğer zamanlarda hızlı (1 sn altında). Bunun neden olduğunu bilmiyorum ve SQL makine (4 çekirdekli, 32 GB) başka uygulamalar tarafından kullanılmadığı için beni deli ediyor ve bu sorgular bu kadar uzun sürmemeli.

Bir DBA veya SQL Server gurusu olmamak, sorunu anlamama yardımcı olabilecek bazı şeylere bakmaya çalışıyorum. Sorunu ve şu ana kadar öğrendiklerimi çözmek için attığım adımlar şunlardır:

  • Uygulama tarafından çağrılan tüm TSQL kodu saklı yordamlarda yazılır.
  • SQL Server profiler üzerinde uzun süren sorguların bazılarını belirledim, ancak bunları Management Studio'da çalıştırdığımda ya çalıştırmak (4 ila 10 saniye arasında) uzun sürebilir ya da hızlı bir şekilde (1 saniyenin altında) çalışabilirler. Parametrelerde geçirilen aynı verilerle tam olarak aynı sorguları çalıştırıyorum. Bu sorgular çoğunlukla içinde belirli ifadeler bulunan saklı yordamlardır.
  • Bazı kaynaklar üzerinde bekleyen süreçler olup olmadığını anlamak için beklemek ve kuyruk istatistiklerine bakmaya çalıştım. Aşağıdaki sorguyu çalıştırdım:

WITH Waits AS
    (SELECT
        wait_type,
        wait_time_ms / 1000.0 AS WaitS,
        (wait_time_ms - signal_wait_time_ms) / 1000.0 AS ResourceS,
        signal_wait_time_ms / 1000.0 AS SignalS,
        waiting_tasks_count AS WaitCount,
        100.0 * wait_time_ms / SUM (wait_time_ms) OVER() AS Percentage,
        ROW_NUMBER() OVER(ORDER BY wait_time_ms DESC) AS RowNum
    FROM sys.dm_os_wait_stats
    WHERE wait_type NOT IN (
        'CLR_SEMAPHORE', 'LAZYWRITER_SLEEP', 'RESOURCE_QUEUE', 'SLEEP_TASK',
        'SLEEP_SYSTEMTASK', 'SQLTRACE_BUFFER_FLUSH', 'WAITFOR', 'LOGMGR_QUEUE',
        'CHECKPOINT_QUEUE', 'REQUEST_FOR_DEADLOCK_SEARCH', 'XE_TIMER_EVENT',  'BROKER_TO_FLUSH',
        'BROKER_TASK_STOP', 'CLR_MANUAL_EVENT', 'CLR_AUTO_EVENT',     'DISPATCHER_QUEUE_SEMAPHORE',
        'FT_IFTS_SCHEDULER_IDLE_WAIT', 'XE_DISPATCHER_WAIT', 'XE_DISPATCHER_JOIN', 'BROKER_EVENTHANDLER',
        'TRACEWRITE', 'FT_IFTSHC_MUTEX', 'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',
        'BROKER_RECEIVE_WAITFOR', 'ONDEMAND_TASK_QUEUE', 'DBMIRROR_EVENTS_QUEUE',
        'DBMIRRORING_CMD', 'BROKER_TRANSMITTER', 'SQLTRACE_WAIT_ENTRIES',
        'SLEEP_BPOOL_FLUSH', 'SQLTRACE_LOCK')
    )
SELECT
    W1.wait_type AS WaitType, 
    CAST (W1.WaitS AS DECIMAL(14, 2)) AS Wait_S,
    CAST (W1.ResourceS AS DECIMAL(14, 2)) AS Resource_S,
    CAST (W1.SignalS AS DECIMAL(14, 2)) AS Signal_S,
    W1.WaitCount AS WaitCount,
    CAST (W1.Percentage AS DECIMAL(4, 2)) AS Percentage,
    CAST ((W1.WaitS / W1.WaitCount) AS DECIMAL (14, 4)) AS AvgWait_S,
    CAST ((W1.ResourceS / W1.WaitCount) AS DECIMAL (14, 4)) AS AvgRes_S,
    CAST ((W1.SignalS / W1.WaitCount) AS DECIMAL (14, 4)) AS AvgSig_S
FROM Waits AS W1
    INNER JOIN Waits AS W2 ON W2.RowNum <= W1.RowNum
GROUP BY W1.RowNum, W1.wait_type, W1.WaitS, W1.ResourceS, W1.SignalS, W1.WaitCount,    W1.Percentage
HAVING SUM (W2.Percentage) - W1.Percentage < 95; -- percentage threshold
GO

İşte buldum:

  • İstatistikleri DBCC SQLPERF kullanarak sıfırladıktan sonra (yaklaşık 1 veya 2 saat sonra), en çok sahip olduğum bekleme türleri SOS_SCHEDULER_YIELD ve WRITELOG
  • Zaman içinde (yaklaşık 1 günlük uygulamadan sonra), her biri için ortalama bekleme süresi uzun olmasa da, veritabanında en çok meydana gelen bekleme türleri CXPACKET (% 67) ve OLEDB'dir (% 17). Ayrıca SQL Profiler üzerinde tanımlanan uzun çalışan ifadeler birden fazla sonuç kümesi (genellikle 3) döndürülen saklı yordamlar çağrıları olduğunu fark ettim. Burada bir paralellik sorunu olabilir mi? Sorunun sebebinin bu olup olmadığını belirlemeye çalışabileceğim herhangi bir yol var mı?
  • OLEDB beklemelerinin bağlantılı sunucular gibi OLEDB kaynaklarına yapılan çağrılardan kaynaklanabileceğini bir yerde okudum. Bir Dizin Oluşturma Hizmetleri makinesine (MSIDXS) bağlanmak için bağlantılı bir sunucumuz var, ancak uzun süre çalıştığı belirtilen ifadelerin hiçbiri bu bağlantılı sunucuyu kullanmıyor.
  • Sahip olduğum daha yüksek ortalama bekleme süresi LCK_M_X tipi beklemeler içindir (ortalama yaklaşık 1,5 sn), ancak bu bekleme türleri diğer türlerle karşılaştırıldığında çok sık gerçekleşmez (örneğin, 64 LCK_M_X bekler ve 10,823 CXPACKET aynı süre bekler ).
  • Fark ettiğim bir şey, MSDTC hizmetinin kümelenmemiş olmasıdır. SQL Server hizmeti kümelenmiş ancak MSDTC değil. Bu nedenle bir performans isabeti olabilir mi? Uygulamamız veritabanına erişmek için Enterprise Services (DCOM) kullandığından MSDTC kullanıyoruz, ancak sunucular tarafımızdan değil, istemcimiz tarafından yüklenip yapılandırıldı.

Herkes bu veriler hakkında daha fazla anlam ifade etmeme yardımcı olabilir mi? Biri bana neler olabileceğini anlama konusunda yardım edebilir mi? Sunucuda bir şeyler bulmaya çalışmak için yapabileceğim bir şey var mı? Uygulama geliştirme ekibiyle konuşmalı mıyım?

Yanıtlar:


4

Sorununuzun ayrıntılı açıklaması için teşekkür ederiz (aslında ortaya konan en iyi sorulardan biri).

WRITELOG çok yaygın bir bekleme türüdür, bu yüzden endişelenmeyin. SOS_SCHEDULER_YIELD, CPU basıncını ve ayrıca CXPACKET'i gösterirse, bazı eksik dizinler olması gerekebilir ve bir OLTP sistemi için sorgulardan çok fazla veri alıyor olabilirsiniz. Kayıp Endeksler DMV'sine bakmanızı ve şüpheli prokste olan herhangi bir endeks olup olmadığını (neredeyse çok az olacağından emin olun) görmenizi öneririm.

http://sqlfool.com/2009/04/a-look-at-missing-indexes/

http://troubleshootingsql.com/2009/12/30/how-to-find-out-the-missing-indexes-on-a-sql-server-2008-or-2005-instance-along-with-the- create-index-komutları /

Bu konuda Jonathan Kehayias'ın sqlblog.com'daki gönderisine de bakın.

Ayrıca, Parametre koklamaya da bakınız.

http://sommarskog.se/query-plan-mysteries.html

http://pratchev.blogspot.com/2007/08/parameter-sniffing.html

İhtiyaçlarınız için rekabet cevabı değil, iyi bir başlangıç ​​noktasıdır. Daha fazla ayrıntıya ihtiyacınız varsa bize bildirin.


1

Çalışanlardan biri saklı yordamların birkaçını yeniden yazdıktan sonra da benzer bir sorun yaşadık. Aşırı dallanma olduğu ve nerede yan tümcesini önemli ölçüde değiştiren Dinamik SQL oluşturulduğu ortaya çıktı .

Örneğin (basitleştirilmiş):

Eğer Modeli "X" idi aradı nerede fıkra ProductCode belirli değerlere eşittir.
Eğer Modeli "Y" idi aradı nerede fıkra ProductType belirli değerlere eşittir.

SQL Server, saklı yordam ilk çalıştırıldığında giriş parametrelerine dayalı bir sorgu planı oluşturur. Bu nedenle, sorgu planı "ProductCode" kullanan mantık üzerine kuruluysa ve "ProductType" sorgusuna eşitse, bu eşleşmeyen bir sorgu planıdır ve büyük olasılıkla tam tablo taramasıyla sonuçlanır.

Saklı yordamın üstüne " RECOMPILE İLE " yerleştirmeyi deneyebilirsiniz . PROSEDÜR OLUŞTUR (Transact-sql)

Bunu tanımlamanın en iyi yolu şöyledir:

Soyadına göre sıralanmış bir adlar ve telefon numaraları listeniz olduğunu varsayalım. Bu, Soyadlarını (Soyadına dayalı sorgu planı) kullanan kişileri bulmak için harika çalışır. Şimdi Alan Kodu 203'teki tüm isimlere ve telefon numaralarına ihtiyacınız olduğunu varsayalım. Listeniz Soyadına göre sıralandıysa, tüm Alan Kodu 203 kişilerin tam bir listesini almanın tek yolu üstten başlamak ve her birini sırayla okumaktır. her kayıt. (Tam Tablo Tarama).


exec()Fonksiyonu kullanmak gözlemlenen davranışı açıklar. Bu durumda sp_executesqlnormal olarak kullanmak dinamik SQL ifadeleriyle ilgili sorunları çözer.
ajeh

1

Sorgular SSMS ve uygulamada aralıklı olarak hızlı ve yavaş çalışıyorsa, bir istatistik veya parametre koklama sorununuz olabilir.

Bu saklı yordamları yürütmek, sonra kök operatörü (her deyimin en solundaki yeşil düğüm) özelliklerini almak için yürütme planını gözden geçirin.

Yürütme planındaki tahmini satır sayısı nedir, kaç gerçek satır döndürüldü?

Derlenen parametre gerçek sorgu parametresiyle eşleşiyor mu?

Yürütme planı yalnızca bir avuç satır döndüren bir parametre için oluşturulduysa ve aynı yordamı çok sayıda satır döndüren bir parametreyle çalıştırırsanız, SQL sorgu için yanlış yürütme planını kullanabilir.

Yürütme planı seçimleri SQL istatistikleriyle yakından bağlantılıdır, bu nedenle istatistiklerinizi düzenli olarak yeniden oluşturmak iyi bir fikirdir.

Sağlanan parametreye bağlı olarak bazen az miktarda veri veya çok miktarda veri döndüren bir saklı yordamınız varsa, parametre koklama sorununuz olabilir.

İstatistiklerinizi yeniden oluşturmak sorunu çözmezse, saklı yordamdaki en pahalı ifadeleri OPTION (RECOMPILE)


0

Uzun süren sorgular belirlediğiniz için, bu yordamlar için yürütme planlarını önbelleğinizden alabilir ve sorunu burada belirleyip belirleyemeyeceğinizi görebilirsiniz. Genellikle veri türlerinin örtük veya çalışma zamanı dönüşümleri vardır. Ayrıca, çok fazla veri temizlerseniz veya eklerseniz, istatistikleri de güncellemeniz önerilir.

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.