Depolanan prosedür web'den çağrıldığında yavaş, Management Studio'dan hızlı


97

Web uygulamasından her çağrıldığında delicesine zaman aşımına uğrayan saklı yordamım var.

Sql Profiler'ı çalıştırdım ve zaman aşımına uğrayan çağrıları izledim ve sonunda şunları öğrendim:

  1. İfadeleri MS SQL Management Studio içinden aynı argümanlarla çalıştırdığınızda (aslında prosedür çağrısını sql profil izlemesinden kopyaladım ve çalıştırdım): Ortalama 5 ~ 6 saniye içinde bitiyor.
  2. Ancak web uygulamasından çağrıldığında, 30 saniyeden fazla sürüyor (izleme olarak), bu nedenle web sayfam o zamana kadar gerçekten zaman aşımına uğradı.

Web uygulamamın kendi kullanıcısı olması dışında her şey aynı (aynı veritabanı, bağlantı, sunucu vb.) Web uygulamasının kullanıcısıyla doğrudan stüdyoda sorgu çalıştırmayı denedim ve 6'dan fazla sürmüyor sn.

Neler olduğunu nasıl anlarım?

İz, gecikmenin gerçek prosedürde olduğunu açıkça gösterdiğinden, BLL> DAL katmanlarını veya Tablo adaptörlerini kullandığımız gerçeğiyle hiçbir ilgisi olmadığını varsayıyorum. Tüm düşünebildiğim bu.

DÜZENLE Bu bağlantıda ADO.NET'in ARITHABORTdoğru olarak ayarladığını öğrendim - ki bu çoğu zaman için iyidir, ancak bazen bu olur ve önerilen geçici çözüm, with recompiledepolanan proc'a seçenek eklemek . Benim durumumda çalışmıyor ama buna çok benzer bir şey olduğundan şüpheleniyorum. ADO.NET'in başka ne yaptığını veya özelliklerini nerede bulabileceğimi bilen var mı?


1
Bu, ne kadar verinin döndürüldüğüyle ilgili olabilir mi?
Barry Kaye

@Barry: Hayır, aynı prosedürü (izlemeden de kopyalandı - aynı parametreler anlamına geliyor) yönetim stüdyosunda çalıştırdığım için 6 saniye içinde çalışıyor.
iamserious

@Jayantha: Konu, sp'nin yavaş olması DEĞİL, ancak ado.net ve sql arasında BİR ŞEY var. Sp'nin nasıl bir fark yaratacağını anlamıyorum.
iamserious

2
SP çok fazla veri döndürüyor mu, örneğin resim / metin / varchar (maks.) Sütunları? İstemci üzerinde tüketilecek veri miktarı çok büyük olacak ve bu çok zaman alacaktır. SSMS, bu sonuç kümelerini daha verimli bir şekilde keser.
Tim Schmelter

Yanıtlar:


79

Geçmişte de benzer bir sorun yaşadım, bu yüzden bu sorunun çözümünü görmek için sabırsızlanıyorum. Aaron Bertrand'ın OP hakkındaki yorumu, Sorgunun web'den yürütüldüğünde zaman aşımına uğramasına, ancak SSMS'den yürütüldüğünde süper hızlı olmasına yol açtı ve soru bir kopya olmasa da, yanıt durumunuz için çok iyi geçerli olabilir.

Temelde, SQL Server'da bozuk bir önbelleğe alınmış yürütme planı olabilir gibi görünüyor. Web sunucunuzla kötü plana vuruyorsunuz, ancak ARITHABORT bayrağında farklı bir ayar olduğu için SSMS farklı bir plana çıkıyor (aksi takdirde sizin özel sorgunuz / depolanan işlem üzerinde hiçbir etkisi olmayacaktı).

Bkz ADO.NET arayarak T-SQL Saklı Yordam bir SqlTimeoutException neden daha eksiksiz bir açıklama ve çözünürlükte, başka örneğin.


Bunlar bazı ilginç ipuçları, onlar hakkında daha fazla bilgi okuyacak ve birkaç dakika içinde geri dönecek .. teşekkürler.
iamserious

46
Merhaba, Önbelleği temizlemek DBCC DROPCLEANBUFFERSve DBCC FREEPROCCACHEhile yaptım! Yürütme planının bir şekilde bozuk olduğunu veya güncellenmediğini tahmin ediyorum. Kalıcı bir düzeltme olduğundan şüpheliyim, eğer bir kez bozulabilirse, tekrar yapabilir. Bu yüzden hala makul nedenleri araştırıyorum. Web uygulaması tekrar çalışmaya başladığından, baskıyı hissetmeme gerek yok. Çok teşekkürler.
iamserious

2
@iamserious - başardın teşekkürler! Depolanan yordamımı değiştirdikten sonra zaman aşımı sorunu yaşıyordum. Sonra yukarıda bahsettiğiniz iki DBCC komutunu çalıştırdım ve sorunu çözdü.
Induster

5
@Mangist: Bu karmaşık bir konu olduğu için, sihirli bir değnek yoktur, ancak sorunlara neden olan sorgularda ipuçlarını kullanmayı deneyebilir OPTIMIZE FORveya OPTION(Recompile)sorgulayabilirsiniz. Bu makale sorunu derinlemesine tartışmaktadır. Entity Framework sorgularınızı oluşturuyorsa, bu gönderi sorgularınıza bir sorgu ipucu eklemek için bir yol sağlar.
StriplingWarrior

8
TÜM yürütme planlarını temizleyecek olan DBCC DROPCLEANBUFFERS ve DBCC FREEPROCCACHE'ı çalıştırmak yerine, sorunlu saklı yordamı bırakabilir ve yeniden oluşturabilirsiniz.
jnoreiga

52

Ayrıca sorguların web'den yavaş ve SSMS'de hızlı çalıştığını da deneyimledim ve sonunda sorunun parametre koklama denen bir şey olduğunu öğrendim.

Benim için düzeltme, sproc'ta kullanılan tüm parametreleri yerel değişkenlerle değiştirmekti.

Örneğin. değişiklik:

ALTER PROCEDURE [dbo].[sproc] 
    @param1 int,
AS
SELECT * FROM Table WHERE ID = @param1 

to:

ALTER PROCEDURE [dbo].[sproc] 
    @param1 int,
AS
DECLARE @param1a int
SET @param1a = @param1
SELECT * FROM Table WHERE ID = @param1a

Garip görünüyor ama sorunumu çözdü.


3
Vay canına, aynı sorunu yaşadım ve bunun işe yarayacağına inanmadım ama işe yaradı.
Lac Ho

1
Zane, bunun sorunu kalıcı olarak çözüp çözmeyeceğini biliyor musun yoksa geri gelebilir mi? Teşekkür ederim!
Lac Ho

1
Bu değişikliği yaptığımdan beri, saklı yordamın hızıyla ilgili herhangi bir sorun yaşamadım.
Zane

1
Vay canına, benim de sorunumu çözdü! Bu, sql sunucusunda bir hata OLMALIDIR. MSSQL, BÜYÜK performans kazanımları için dahili olarak kaputun altında yerele dönüştüğünde sql yazarlarını neden bu aptal çemberden atlamaya zorlayasınız ki?
HerrimanCoder

3
İşlemi değiştirmek, yeni bir yürütme planının oluşturulmasına neden olabilir, bu nedenle çözüm, girdi değişkenini yerel bir değişkene gerçekten kopyalamak değil, sadece yeni bir yürütme planının oluşturulmasını zorlamak olabilir mi (kabul edilen çözümde açıklandığı gibi)?
Garland Pope

10

İstenmeyen posta değil, ancak diğerleri için yararlı bir çözüm olarak, sistemimiz yüksek derecede zaman aşımına uğradı.

Depolanan yordamı kullanarak yeniden derlenecek şekilde ayarlamayı denedim sp_recompileve bu, bir SP için sorunu çözdü.

Nihayetinde zaman aşımına uğrayan çok sayıda SP vardı, bunların çoğu daha önce hiç yapılmamıştı DBCC DROPCLEANBUFFERSve DBBC FREEPROCCACHEzaman aşımlarının olay oranı önemli ölçüde düştü - hala bazılarının plan yenilemesinin aldığından şüphelendiğim bazı durumlar var. bir süre ve bazıları SP'lerin gerçekten düşük performans gösterdiği ve yeniden değerlendirilmeye ihtiyaç duyduğu yerler.


1
Bunun için teşekkürler. Sp_recompile komutunu kullanarak yeniden derleme prosedürünü işaretlemek benim için çalıştı DBCC DROPCLEANBUFFERSve DBCC FREEPROCCACHEhiçbir fark yaratmadı .
Steve

4

Web uygulaması, SP'yi aramadan önce yapılan diğer bazı DB çağrılarının bir işlemi açık tutması olabilir mi? Bu SP'nin web uygulaması tarafından çağrıldığında beklemesinin bir nedeni olabilir. Web uygulamasındaki bazı önceki eylemlerin bu soruna neden olduğundan emin olmak için aramayı web uygulamasında izole edin (yeni bir sayfaya koyun) derim.


1
Merhaba @Tundey, aramayı izole ettim ve hala yaklaşık 30 saniye sürüyor ve zaman aşımına uğradı. yani iletişim arasında bir şey olmalı, sanırım?
iamserious

1

Sadece saklı yordamı yeniden derlemek (benim durumumda tablo işlevi) benim için çalıştı


1

@ Zane'in söylediği gibi bunun parametre koklamadan kaynaklanabileceğini söyledi. Aynı davranışı yaşadım ve prosedürün yürütme planına ve bir satırdaki sp'nin tüm ifadelerine bir göz attım (prosedürden tüm ifadeleri kopyaladım, parametreleri değişken olarak açıkladım ve değişken için aynı değerleri atadım. parametreler vardı). Ancak uygulama planı tamamen farklı görünüyordu. Sp yürütme 3-4 saniye sürdü ve aynı değerlere sahip art arda ifadeler anında döndürüldü.

Yürütme planı

Biraz googling yaptıktan sonra bu davranış hakkında ilginç bir okuma buldum: Uygulamada Yavaş, SSMS'de Hızlı?

Prosedürü derlerken, SQL Server @fromdate değerinin değiştiğini bilmez, ancak prosedürü @fromdate değerinin NULL olduğu varsayımı altında derler. NULL ile yapılan tüm karşılaştırmalar BİLİNMEYEN sonuç verdiğinden, @fromdate çalışma zamanında hala bu değere sahipse sorgu hiç satır döndüremez. SQL Server girdi değerini nihai gerçek olarak alırsa, yalnızca tabloya hiç erişmeyen bir Sabit Tarama ile bir plan oluşturabilir (bunun bir örneğini görmek için SELECT * FROM Orders WHERE OrderDate> NULL sorgusunu çalıştırın) . Ancak SQL Server, çalışma zamanında @fromdate değerine sahip olursa olsun doğru sonucu döndüren bir plan oluşturmalıdır. Öte yandan, tüm değerler için en iyisi olan bir plan inşa etme zorunluluğu yoktur. Bu nedenle, varsayım hiçbir satırın döndürülmeyeceği olduğu için, SQL Server Dizin Arama için yerleşir.

Sorun şu ki, boş bırakılabilecek parametrelerim vardı ve bunlar boş olarak geçirilirse, varsayılan bir değerle başlatılacaktı.

create procedure dbo.procedure
    @dateTo datetime = null
begin
    if (@dateTo is null)
    begin
        select @dateTo  = GETUTCDATE()
    end

    select foo
    from dbo.table
    where createdDate < @dateTo
end

Olarak değiştirdikten sonra

create procedure dbo.procedure
    @dateTo datetime = null
begin
    declare @to datetime = coalesce(@dateTo, getutcdate())

    select foo
    from dbo.table
    where createdDate < @to
end 

yine bir cazibe gibi çalıştı.


0
--BEFORE
CREATE PROCEDURE [dbo].[SP_DEMO]
( 
    @ToUserId bigint=null
 )
AS
BEGIN
SELECT * FROM tbl_Logins WHERE LoginId = @ToUserId 
END
--AFTER CHANGING TO IT WORKING FINE
CREATE PROCEDURE [dbo].[SP_DEMO]
( 
    @ToUserId bigint=null
 )
AS
BEGIN
DECLARE @Toid bigint=null
SET @Toid=@ToUserId
SELECT * FROM tbl_Logins WHERE LoginId = @Toid 
END
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.