SQL Server: Hızlı sorgula, ancak yordamdan yavaş


257

Bir sorgu hızlı çalışır:

DECLARE @SessionGUID uniqueidentifier
SET @SessionGUID = 'BCBA333C-B6A1-4155-9833-C495F22EA908'

SELECT *
FROM Report_Opener
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank

alt ağaç maliyeti: 0.502

Ancak aynı SQL'i saklı bir yordama koymak yavaş çalışır ve tamamen farklı bir yürütme planıyla

CREATE PROCEDURE dbo.ViewOpener @SessionGUID uniqueidentifier AS
SELECT *
FROM Report_Opener
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank

EXECUTE ViewOpener @SessionGUID

Ağaç maliyeti: 19.2

Koştum

sp_recompile ViewOpener

Ve hala aynı (kötü) çalışıyor ve ben de saklı yordamı değiştirdim

CREATE PROCEDURE dbo.ViewOpener @SessionGUID uniqueidentifier AS
SELECT *, 'recompile please'
FROM Report_Opener
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank

Ve tekrar, gerçekten yeniden derlemeye kandırmaya çalışıyor.

Yeni bir plan oluşturmasını sağlamak için saklı yordamı bıraktım ve yeniden oluşturdum.

Bir derleme değişkeni kullanarak yeniden derleme zorlama ve parametre koklama önlemek denedim :

CREATE PROCEDURE dbo.ViewOpener @SessionGUID uniqueidentifier AS

DECLARE @SessionGUIDbitch uniqueidentifier
SET @SessionGUIDbitch = @SessionGUID

SELECT *
FROM Report_Opener
WHERE SessionGUID = @SessionGUIDbitch
ORDER BY CurrencyTypeOrder, Rank

Ayrıca saklı yordamı tanımlamayı denedim WITH RECOMPILE:

CREATE PROCEDURE dbo.ViewOpener @SessionGUID uniqueidentifier 
WITH RECOMPILE
AS
SELECT *
FROM Report_Opener
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank

Böylece planı asla önbelleğe alınmaz ve ben yürütme sırasında bir derleme zorlamaya çalıştım:

EXECUTE ViewOpener @SessionGUID WITH RECOMPILE

Hangi yardımcı olmadı.

Yordamı dinamik SQL'e dönüştürmeyi denedim:

CREATE PROCEDURE dbo.ViewOpener @SessionGUID uniqueidentifier 
WITH RECOMPILE AS
DECLARE @SQLString NVARCHAR(500)

SET @SQLString = N'SELECT *
   FROM Report_OpenerTest
   WHERE SessionGUID = @SessionGUID
   ORDER BY CurrencyTypeOrder, Rank'

EXECUTE sp_executesql @SQLString,
N'@SessionGUID uniqueidentifier',
@SessionGUID

Hangi yardımcı olmadı.

" Report_Opener" Öğesi, dizine eklenmemiş bir görünümdür. Görünüm yalnızca temel tablolara başvurur. Hiçbir tablo, dizinlenmiş veya başka bir şekilde hesaplanmış sütunlar içermez.

Onun cehennemi için görünümü oluşturmaya çalıştım

SET ANSI_NULLS ON
SET QUOTED_IDENTIFER ON

Bu sorunu çözmedi.

Nasıl yani

  • sorgu hızlı
  • sorguyu bir görünüme taşımak ve görünümden seçim yapmak hızlı
  • saklı yordamdan görünümden seçim yapmak 40 kat daha yavaş mı?

Görünüm tanımını doğrudan saklı yordama taşımaya çalıştım (3 iş kuralını ihlal edip önemli bir kapsüllemeyi kırma) ve bu sadece yaklaşık 6 kat daha yavaş yapıyor.

Saklı yordam sürümü neden bu kadar yavaş? Ad-hoc SQL'i farklı bir tür ad-hoc SQL'den daha hızlı çalıştıran SQL Server'ı hesaba katmak ne olabilir?

Gerçekten istemem

  • SQL koduna göm
  • kodu hiç değiştir

    Microsoft SQL Server  2000 - 8.00.2050 (Intel X86)
    Mar  7 2008 21:29:56
    Copyright (c) 1988-2003 Microsoft Corporation
    Standard Edition on Windows NT 5.2 (Build 3790: Service Pack 2)
    

Ancak, SQL Server'ın parametre koklaması olmasa bile bir sorguyu çalıştıran SQL Sever kadar hızlı çalışamaması ne olabilir?


Benim sonraki girişimi olması olacaktır StoredProcedureAçağrı StoredProcedureBçağrı StoredProcedureCçağrı StoredProcedureDgörünümünü sorgulamak için.

Ve başarısız olursa, saklı yordam bir saklı yordamı çağırmak, bir UDF çağırmak, bir UDF çağırmak, bir saklı yordam çağırmak, görünümü sorgulamak için bir UDF çağırmak.


Özetle, aşağıdakiler KG'den hızlı bir şekilde çalışır, ancak saklı bir yordama yerleştirildiğinde yavaşlar:

Orijinal:

--Runs fine outside of a stored procedure
SELECT *
FROM Report_OpenerTest
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank

sp_executesql:

--Runs fine outside of a stored procedure
DECLARE @SQLString NVARCHAR(500)
SET @SQLString = N'SELECT *
FROM Report_OpenerTest
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank'

EXECUTE sp_executesql @SQLString,
        N'@SessionGUID uniqueidentifier',
        @SessionGUID

EXEC(@sql):

--Runs fine outside of a stored procedure
DECLARE @sql NVARCHAR(500)
SET @sql = N'SELECT *
FROM Report_OpenerTest
WHERE SessionGUID = '''+CAST(@SessionGUID AS varchar(50))+'''
ORDER BY CurrencyTypeOrder, Rank'

EXEC(@sql)

Uygulama Planları

İyi Planı:

      |--Sort(ORDER BY:([Expr1020] ASC, [Currencies].[Rank] ASC))
           |--Compute Scalar(DEFINE:([Expr1020]=If ([Currencies].[CurrencyType]='ctCanadianCash') then 1 else If ([Currencies].[CurrencyType]='ctMiscellaneous') then 2 else If ([Currencies].[CurrencyType]='ctTokens') then 3 else If ([Currencies].[CurrencyType]
                |--Nested Loops(Left Outer Join, OUTER REFERENCES:([Openers].[OpenerGUID]))
                     |--Filter(WHERE:((([Currencies].[IsActive]<>0 AND [Currencies].[OnOpener]<>0) AND ((((((([Currencies].[CurrencyType]='ctUSCoin' OR [Currencies].[CurrencyType]='ctMiscellaneousUS') OR [Currencies].[CurrencyType]='ctUSCash') OR [Currencies].
                     |    |--Nested Loops(Left Outer Join, OUTER REFERENCES:([Currencies].[CurrencyGUID], [Openers].[OpenerGUID]) WITH PREFETCH)
                     |         |--Nested Loops(Left Outer Join)
                     |         |    |--Bookmark Lookup(BOOKMARK:([Bmk1016]), OBJECT:([GrobManagementSystemLive].[dbo].[Windows]))
                     |         |    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([Openers].[WindowGUID]))
                     |         |    |         |--Bookmark Lookup(BOOKMARK:([Bmk1014]), OBJECT:([GrobManagementSystemLive].[dbo].[Openers]))
                     |         |    |         |    |--Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[Openers].[IX_Openers_SessionGUID]), SEEK:([Openers].[SessionGUID]=[@SessionGUID]) ORDERED FORWARD)
                     |         |    |         |--Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[Windows].[IX_Windows]), SEEK:([Windows].[WindowGUID]=[Openers].[WindowGUID]) ORDERED FORWARD)
                     |         |    |--Clustered Index Scan(OBJECT:([GrobManagementSystemLive].[dbo].[Currencies].[IX_Currencies_CurrencyType]))
                     |         |--Clustered Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[OpenerDetails].[IX_OpenerDetails_OpenerGUIDCurrencyGUID]), SEEK:([OpenerDetails].[OpenerGUID]=[Openers].[OpenerGUID] AND [OpenerDetails].[CurrencyGUID]=[Currenc
                     |--Hash Match(Cache, HASH:([Openers].[OpenerGUID]), RESIDUAL:([Openers].[OpenerGUID]=[Openers].[OpenerGUID]))
                          |--Stream Aggregate(DEFINE:([Expr1006]=SUM(If (((([Currencies].[CurrencyType]='ctMiscellaneous' OR [Currencies].[CurrencyType]='ctTokens') OR [Currencies].[CurrencyType]='ctChips') OR [Currencies].[CurrencyType]='ctCanadianCoin') OR [
                               |--Nested Loops(Inner Join, OUTER REFERENCES:([OpenerDetails].[CurrencyGUID]) WITH PREFETCH)
                                    |--Nested Loops(Inner Join)
                                    |    |--Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[Openers].[IX_Openers_OneOpenerPerSession]), SEEK:([Openers].[OpenerGUID]=[Openers].[OpenerGUID]) ORDERED FORWARD)
                                    |    |--Clustered Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[OpenerDetails].[IX_OpenerDetails_OpenerGUIDCurrencyGUID]), SEEK:([OpenerDetails].[OpenerGUID]=[Openers].[OpenerGUID]) ORDERED FORWARD)
                                    |--Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[Currencies].[PK_Currencies_CurrencyGUID]), SEEK:([Currencies].[CurrencyGUID]=[OpenerDetails].[CurrencyGUID]) ORDERED FORWARD)

kötü planı

       |--Sort(ORDER BY:([Expr1020] ASC, [Currencies].[Rank] ASC))
            |--Compute Scalar(DEFINE:([Expr1020]=If ([Currencies].[CurrencyType]='ctCanadianCash') then 1 else If ([Currencies].[CurrencyType]='ctMiscellaneous') then 2 else If ([Currencies].[CurrencyType]='ctTokens') then 3 else If ([Currencies].[Currency
                 |--Nested Loops(Left Outer Join, OUTER REFERENCES:([Openers].[OpenerGUID]))
                      |--Filter(WHERE:((([Currencies].[IsActive]<>0 AND [Currencies].[OnOpener]<>0) AND ((((((([Currencies].[CurrencyType]='ctUSCoin' OR [Currencies].[CurrencyType]='ctMiscellaneousUS') OR [Currencies].[CurrencyType]='ctUSCash') OR [Currenc
                      |    |--Nested Loops(Left Outer Join, OUTER REFERENCES:([Currencies].[CurrencyGUID], [Openers].[OpenerGUID]) WITH PREFETCH)
                      |         |--Filter(WHERE:([Openers].[SessionGUID]=[@SessionGUID]))
                      |         |    |--Concatenation
                      |         |         |--Nested Loops(Left Outer Join)
                      |         |         |    |--Table Spool
                      |         |         |    |    |--Hash Match(Inner Join, HASH:([Windows].[WindowGUID])=([Openers].[WindowGUID]), RESIDUAL:([Windows].[WindowGUID]=[Openers].[WindowGUID]))
                      |         |         |    |         |--Clustered Index Scan(OBJECT:([GrobManagementSystemLive].[dbo].[Windows].[IX_Windows_CageGUID]))
                      |         |         |    |         |--Table Scan(OBJECT:([GrobManagementSystemLive].[dbo].[Openers]))
                      |         |         |    |--Table Spool
                      |         |         |         |--Clustered Index Scan(OBJECT:([GrobManagementSystemLive].[dbo].[Currencies].[IX_Currencies_CurrencyType]))
                      |         |         |--Compute Scalar(DEFINE:([Openers].[OpenerGUID]=NULL, [Openers].[SessionGUID]=NULL, [Windows].[UseChipDenominations]=NULL))
                      |         |              |--Nested Loops(Left Anti Semi Join)
                      |         |                   |--Clustered Index Scan(OBJECT:([GrobManagementSystemLive].[dbo].[Currencies].[IX_Currencies_CurrencyType]))
                      |         |                   |--Row Count Spool
                      |         |                        |--Table Spool
                      |         |--Clustered Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[OpenerDetails].[IX_OpenerDetails_OpenerGUIDCurrencyGUID]), SEEK:([OpenerDetails].[OpenerGUID]=[Openers].[OpenerGUID] AND [OpenerDetails].[CurrencyGUID]=[Cu
                      |--Hash Match(Cache, HASH:([Openers].[OpenerGUID]), RESIDUAL:([Openers].[OpenerGUID]=[Openers].[OpenerGUID]))
                           |--Stream Aggregate(DEFINE:([Expr1006]=SUM([partialagg1034]), [Expr1007]=SUM([partialagg1035]), [Expr1008]=SUM([partialagg1036]), [Expr1009]=SUM([partialagg1037]), [Expr1010]=SUM([partialagg1038]), [Expr1011]=SUM([partialagg1039]
                                |--Nested Loops(Inner Join)
                                     |--Stream Aggregate(DEFINE:([partialagg1034]=SUM(If (((([Currencies].[CurrencyType]='ctMiscellaneous' OR [Currencies].[CurrencyType]='ctTokens') OR [Currencies].[CurrencyType]='ctChips') OR [Currencies].[CurrencyType]='
                                     |    |--Nested Loops(Inner Join, OUTER REFERENCES:([OpenerDetails].[CurrencyGUID]) WITH PREFETCH)
                                     |         |--Clustered Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[OpenerDetails].[IX_OpenerDetails_OpenerGUIDCurrencyGUID]), SEEK:([OpenerDetails].[OpenerGUID]=[Openers].[OpenerGUID]) ORDERED FORWARD)
                                     |         |--Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[Currencies].[PK_Currencies_CurrencyGUID]), SEEK:([Currencies].[CurrencyGUID]=[OpenerDetails].[CurrencyGUID]) ORDERED FORWARD)
                                     |--Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[Openers].[IX_Openers_OneOpenerPerSession]), SEEK:([Openers].[OpenerGUID]=[Openers].[OpenerGUID]) ORDERED FORWARD)

Kötü olan, 6 milyon sıra biriktirmeye heveslidir; diğeri değil.

Not: Bu, bir sorguyu ayarlamakla ilgili bir soru değildir. Yıldırım hızlı çalışan bir sorgu var. Ben sadece bir saklı yordam hızlı SQL Server çalıştırmak istiyorum.


Bir parametre alıp başka birisine yeniden atadığınızda ve daha sonra bir sorguda daha sonra kullandığınızda bu gerçekleşebilir ve yanıtın önerdiği gibi @ "someparamname" için en iyi duruma getirme çalışabilir.
JustDave

Yanıtlar:


405

Orijinal posterle aynı problemi yaşadım, ancak alıntılanan cevap benim için sorunu çözmedi. Sorgu, saklı yordamdan hala çok yavaş çalışıyordu.

Burada başka bir cevap buldum "Parametre Sniffing" , Teşekkürler Omnibuzz. Saklı yordam sorgularınızda "yerel Değişkenler" kullanmaya kaynar, ancak daha fazla anlayış için orijinali okuyun, harika bir yazı. Örneğin

Yavaş yol:

CREATE PROCEDURE GetOrderForCustomers(@CustID varchar(20))
AS
BEGIN
    SELECT * 
    FROM orders
    WHERE customerid = @CustID
END

Hızlı yolu:

CREATE PROCEDURE GetOrderForCustomersWithoutPS(@CustID varchar(20))
AS
BEGIN
    DECLARE @LocCustID varchar(20)
    SET @LocCustID = @CustID

    SELECT * 
    FROM orders
    WHERE customerid = @LocCustID
END

Umarım bu başka birine yardımcı olur, bunu yapmak yürütme süremi 5 dakikadan yaklaşık 6-7 saniyeye düşürdü.


23
+1 Ancak, bu çok garip ve bunu tüm prosedürler için yapmalıyız ve eğer yapmazsak, ne zaman yapacağız gibi bir çok soru ortaya çıkıyor.
gotqn

32
Bu davranış karşısında şaşkına dönen tek kişi miyim ?? Parametre koklamasını önlemek için yerel değişkenlerin bildirilmesi gerekiyor ?? SQL Server bunun olmasını engelleyecek kadar akıllı olmamalı mı? Bu, Microsoft'un dar görüşlü IMHO'sunun gereksiz kod şişmesine neden olur.
l46kok

4
15 dakika -> 8 saniye! hayat kurtarıcı
Tony Brix

3
@BennettDill WITH RECOMPILEbenim için bir fark yaratmadı, sadece yerel parametreler.
mrogers

8
Bu, şimdi - OPTION (OPTIMIZE FOR (@varA UNKNOWN, @varB UNKNOWN))
Dave

131

Sorunu buldum, burada saklı yordamın yavaş ve hızlı sürümlerinin komut dosyası:

dbo.ViewOpener__RenamedForCruachan__Slow.PRC

SET QUOTED_IDENTIFIER OFF 
GO
SET ANSI_NULLS OFF 
GO

CREATE PROCEDURE dbo.ViewOpener_RenamedForCruachan_Slow
    @SessionGUID uniqueidentifier
AS

SELECT *
FROM Report_Opener_RenamedForCruachan
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank
GO

SET QUOTED_IDENTIFIER OFF 
GO
SET ANSI_NULLS ON 
GO

dbo.ViewOpener__RenamedForCruachan__Fast.PRC

SET QUOTED_IDENTIFIER OFF 
GO
SET ANSI_NULLS ON 
GO

CREATE PROCEDURE dbo.ViewOpener_RenamedForCruachan_Fast
    @SessionGUID uniqueidentifier 
AS

SELECT *
FROM Report_Opener_RenamedForCruachan
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank
GO

SET QUOTED_IDENTIFIER OFF 
GO
SET ANSI_NULLS ON 
GO

Eğer farkı fark etmediysen, seni suçlamam. Fark, saklı yordamda hiç değil. Hızlı 0,5 maliyet sorgusunu 6 milyon satırlık istekli bir makaraya dönüştüren fark:

Yavaş: SET ANSI_NULLS OFF

Hızlı: SET ANSI_NULLS ON


Bu cevap da mantıklı olabilir, çünkü görüşte şöyle bir katılma maddesi vardır:

(table.column IS NOT NULL)

Yani bazı NULLkatılımcılar var.


Açıklama, Query Analizer'a dönerek ve çalıştırılarak kanıtlanmıştır.

SET ANSI_NULLS OFF

.

DECLARE @SessionGUID uniqueidentifier
SET @SessionGUID = 'BCBA333C-B6A1-4155-9833-C495F22EA908'

.

SELECT *
FROM Report_Opener_RenamedForCruachan
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank

Ve sorgu yavaş.


Sorunun saklı bir yordamdan çalıştırılıyor çünkü sorun değil . Sorun Şirket Müdürünün bağlantı varsayılan seçenek olmasıdır ANSI_NULLS offziyade, ANSI_NULLS onQA varsayılan olan.

Microsoft bu gerçeği KB296769'da kabul eder (Hata: Bağlı sunucu nesneleri içeren saklı yordamlar oluşturmak için SQL Enterprise Manager kullanılamıyor). Geçici çözüm, ANSI_NULLSsaklı yordam iletişim kutusundaki seçeneği içerir :

Set ANSI_NULLS ON
Go
Create Proc spXXXX as
....

2
Hala dönüşün ANSI_NULLS ONbu kadar büyük bir performans farkı yarattığını anlamıyorum .
Justin Helgerson

2
@ Ek0nomik Çünkü JOINgörünümün içindeki cümlelerin ne zaman farklı anlamları vardır ANSI_NULLS OFF. Aniden satırlar eşleşir ve optimize edicinin sorguyu tamamen farklı şekilde çalıştırmasına neden olur. Tüm satırların% 99,9'unu ortadan kaldırmak yerine aniden geri döndüklerini hayal edin.
Ian Boyd

2
Not: ANSI_NULLS OFFkullanımdan kaldırıldı ve kötü bir uygulama olarak kabul edildi
jean

2
link "SQL Server'ın gelecekteki bir sürümünde ANSI_NULLS her zaman AÇIK olur ve seçeneği açıkça KAPALI olarak ayarlayan uygulamalar bir hata oluşturur. Bu özelliği yeni geliştirme çalışmalarında kullanmaktan kaçının ve şu anda bu özelliği kullanan uygulamaları değiştirmeyi planlayın. "
17'de

Benim durumumda yardımcı olmadı.
st_stefanov

19

Bunu veritabanınız için yapın. Aynı sorun var - bir veritabanında iyi çalışıyor ama SSIS Import (her zamanki geri yükleme değil) kullanarak başka bir veritabanına kopyalayın, bu sorun benim saklı yordamların çoğunda olur. Biraz daha googling yaptıktan sonra , Pinal Dave'in blogunu buldum (ki btw, gönderisinin çoğuyla karşılaştım ve bana çok yardımcı oldu, teşekkürler Pinal Dave) .

Veritabanımda aşağıdaki sorguyu yürütmek ve sorunumu düzeltti:

EXEC sp_MSforeachtable @command1="print '?' DBCC DBREINDEX ('?', ' ', 80)"
GO
EXEC sp_updatestats
GO 

Bu yardımcı olur umarım. Bana yardım eden başkalarının yardımını geçtim.


2
Gelecekteki okuyucular için sadece bir FYI: DBCC REINDEXkullanımdan kaldırıldı, bu yüzden alternatifleri aramalısınız.
15'te gvee

1
Sorunum düzeltildi, teşekkürler (1m20s aşağı 2s!). Re:, DBCC DBREINDEXMS diyor ki: "Bu özellik Microsoft SQL Server'ın gelecekteki bir sürümünde kaldırılacaktır. Bu özelliği yeni geliştirme çalışmalarında kullanmayın ve şu anda bu özelliği kullanan uygulamaları değiştirin. Bunun yerine ALTER INDEX kullanın."
AjV Jsy

Bu en iyi cevap olup olmadığını bilmiyorum ama benim durumumda sp_updatestats tüm gereken, yani +1
Todd Menier

..yes ve yeniden oluşturma dizinlerinin zaman ve yer kaplayabileceğini unutmayın, bu yüzden bunu üretim sunucunuzda yürütmeden önce olası yavaşlamayı sağlayabildiğinizden emin olun. REORGANIZE veya REBUILD İLE (ONLINE = ON) bakmanızı öneririm
Milan

14

Aynı sorunla karşı karşıyaydım ve bu yazı benim için çok yararlı oldu, ancak gönderilen cevapların hiçbiri benim özel sorunumu çözmedi. Benim için çalışan çözümü, başka birine yardımcı olabileceği umuduyla göndermek istedim.

https://stackoverflow.com/a/24016676/814299

Sorgunuzun sonuna OPTION (OPTIMIZE FOR (@now UNKNOWN)) ekleyin


4

Bu kez sorununu buldun. Bir dahaki sefere daha az şanslıysanız ve çözemiyorsanız, plan dondurmayı kullanabilir ve yanlış yürütme planı hakkında endişelenmeyi bırakabilirsiniz .


Bu blog girişine göre, plan dondurma sadece MS SQL 2005 ve üstü için, bu yüzden OP yardımcı olmaz.
Coxy

Sorun yanlış sorgu planını kullanmak oldu. yanlış olana dondurmak istemem.
Ian Boyd

4

Bu sorunu yaşıyordum. Sorgum şuna benzer:

select a, b, c from sometable where date > '20140101'

Saklı yordam şöyle tanımlandı:

create procedure my_procedure (@dtFrom date)
as
select a, b, c from sometable where date > @dtFrom

Veri tipini datetime ve voila olarak değiştirdim! 30 dakika ile 1 dakika arasında gitti!

create procedure my_procedure (@dtFrom datetime)
as
select a, b, c from sometable where date > @dtFrom

2
Çok teşekkürler Lee, bu benim günümü kurtardı! Tarih saat alanının yalnızca tarih bölümünü şu şekilde edinebilirim: DATEADD (dd, 0, DATEDIFF (dd, 0, table.field))
Julien B.

1
BU Sorunum düzeltildi. Sütun varchar (20) vardı ve parametre türünü sütun türü ile aynı hale getirdikten sonra parametrem nvarchar (50) idi - artık gecikme yok.
st_stefanov

3

Report_Opener tablosundaki istatistikleri ve / veya dizinleri yeniden oluşturmayı denediniz mi? İstatistikler, veritabanının ilk açılışından itibaren hala veriler gösteriyorsa, SP'nin tüm yeniden eşleşmeleri hiçbir değere değmez.

Optimize edici parametrenin asla boş olmayacağını görebildiğinden ilk sorgunun kendisi hızlı bir şekilde çalışır. SP durumunda, iyileştirici parametrenin asla boş olmayacağından emin olamaz.


Saklı yordam bildiriminde i parametresinin boş olamayacağını belirtmenin bir yolu var mı? Ve bu sp_executesql tarafından düzeltilecek bir şey değil mi?
Ian Boyd

2005'te değil, bir sözcük satırında. 2005, bir parametre için örnek bir değer sağlayabileceğiniz bir sorgu ipucu ekledi, optimize edici, parametrenin her zaman kullanıldığını biliyormuş gibi optimize eder. Genelde bu tür şeyleri bir istatistik problemi olarak bulduğumu söyledikten sonra.
AnthonyWJones

Bir istatistik sorunu varsa, ben ad-hoc, sp_executesql, exec () çalıştırdığınızda QA iyi çalışır. Ve saklı yordam ad-hoc sql, sp_executesql, exec () içerdiğinde neden hepsi zayıf çalışıyor?
Ian Boyd

1

Genellikle buna karşı olduğum halde (bu durumda gerçek bir nedeniniz var gibi görünüyor), sorgunun SP sürümünde herhangi bir sorgu ipucu sağlamayı denediniz mi? SQL Server bu iki durumda farklı bir yürütme planı hazırlıyorsa, planın birincisiyle eşleşmesi için hangi dizinin kullanılacağını söylemek için bir ipucu kullanabilir misiniz?

Bazı örnekler için buraya gidebilirsiniz .

DÜZENLEME: Sorgu planınızı buraya gönderebilirseniz, belki de anlatılan planlar arasında bazı farklar belirleyebiliriz.

İKİNCİ: Bağlantıyı SQL-2000'e özgü olarak güncelledi. Bir yolu aşağı kaydırmanız gerekecek, ancak aradığınız şey olan "Tablo İpuçları" başlıklı ikinci bir başlık var.

ÜÇÜNCÜ: "Kötü" sorgusu, "Açacakları" tablosundaki [IX_Openers_SessionGUID] 'u görmezden geliyor gibi görünüyor - bu dizini kullanmaya zorlamak için bir INDEX ipucu ekleme şansı değişecek mi?


Bu başvurudaki en yararlı sorgu ipuçları, söz konusu sürüm olan SQL 2000'de mevcut değildir.
AnthonyWJones

Ayrıca, hangi ipuçlarına ihtiyaç vardır? SQL Server, ad-hoc çalıştırdığımda sorun çözemedi.
Ian Boyd

Tabii, bu da benim deneyimim oldu. Ancak, bu durumda, tamamen farklı bir yürütme planı hazırladığını söylüyor. Belki ad-hoc kullanılan bir indeks vardır, ancak bir nedenden dolayı proc'ta göz ardı ediliyor. SQL Server'ı "INDEX" ipucuyla dizini kullanmaya zorlayabilir.
SqlRyan

1

Bu muhtemelen olası değildir, ancak gözlemlenen davranışınızın olağandışı olduğu göz önüne alındığında, kontrol edilmesi gerekir ve hiç kimse bundan bahsetmedi.

Tüm nesnelerin dbo'ya ait olduğundan ve kendiniz veya farklı bir kullanıcı tarafından sahip olduğunuz sahte bir kopyaya sahip olmadığınızdan kesinlikle emin misiniz ?

Sadece zaman zaman tuhaf davranışlar gördüğümde, aslında bir nesnenin iki kopyası olduğu ve hangisinin alacağınız neyin belirtildiğine ve kime giriş yaptığınıza bağlıdır. Örneğin, aynı ada sahip ancak farklı sahiplerin sahip olduğu bir görünüm veya prosedürün iki kopyasına sahip olmak mükemmel bir şekilde mümkündür - veritabanına dbo olarak giriş yapmadığınız ve dbo'yu nesne sahibi olarak belirtmeyi unutduğunuz bir durum nesneyi oluşturursunuz.

Metinde, sahibi belirtmeden bazı şeyler çalıştırdığınızı unutmayın.

sp_recompile ViewOpener

Örneğin, dbo ve [başka bir kullanıcı] tarafından sahip olunan iki viewOpener kopyasının, burada belirtmediğiniz takdirde gerçekte yeniden derlediğiniz koşullara bağlıdır. Report_Opener görünümü ile Ditto - iki kopya varsa (ve özellik veya yürütme planında farklılık gösterebilirse), o zaman kullanılan şey koşullara bağlıdır - ve sahibi belirtmediğiniz için, adhoc sorgunuzun birini ve derlenmiş prosedür diğerini kullanabilir.

Dediğim gibi, muhtemelen olası değildir, ancak olasıdır ve kontrol edilmelidir, çünkü sorunlarınız sadece hatayı yanlış yerde aradığınız olabilir.


1

Bu aptalca gelebilir ve SessionGUID adından bariz görünebilir, ancak sütun Report_Opener'da benzersiz bir tanımlayıcı mıdır? Değilse, doğru türe yayınlamayı denemek ve bir deneme yapmak veya değişkeninizi doğru türe beyan etmek isteyebilirsiniz.

Sproc'un bir parçası olarak oluşturulan plan istemeden çalışabilir ve büyük bir masaya dahili bir döküm yapabilir.


O değil. Ama ben bir varcharsütun nvarchardeğeri (örneğin WHERE CustomerName = N'zrendall') ile karşılaştırıyor nerede bir yan tümcesi ile performans sorunları gördüm . SQL Server nvarcharkarşılaştırma önce her sütun değerini bir yukarı dönüştürmek zorunda kaldı .
Ian Boyd

0

Başka bir fikrim var. Bu tablo tabanlı işlevi oluşturursanız:

CREATE FUNCTION tbfSelectFromView
(   
    -- Add the parameters for the function here
    @SessionGUID UNIQUEIDENTIFIER
)
RETURNS TABLE 
AS
RETURN 
(
    SELECT *
    FROM Report_Opener
    WHERE SessionGUID = @SessionGUID
    ORDER BY CurrencyTypeOrder, Rank
)
GO

Ve sonra aşağıdaki ifadeyi kullanarak seçin (bunu SP'nize koyarak bile):

SELECT *
FROM tbfSelectFromView(@SessionGUID)

Görünüşe göre (herkes zaten yorumladı) SQL Server sadece yanlış bir yerde bir varsayım yapar ve belki de bu varsayımı düzeltmeye zorlar. Fazladan bir adım eklemekten nefret ediyorum, ama başka nelere sebep olabileceğinden emin değilim.


0

- İşte çözüm:

create procedure GetOrderForCustomers(@CustID varchar(20))

as

begin

select * from orders

where customerid = ISNULL(@CustID, '')

end

-- Bu kadar

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.