SQL Server:クエリは高速ですが、手順が遅い


257

クエリは高速に実行されます。

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

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

サブツリーコスト:0.502

しかし、同じSQLをストアドプロシージャに配置すると、実行速度が遅くなり、実行プランがまったく異なります。

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

EXECUTE ViewOpener @SessionGUID

サブツリーのコスト:19.2

私は走った

sp_recompile ViewOpener

そして、それはまだ同じように(悪い)実行されます、そして私はストアドプロシージャもに変更しました

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

そして再び、それを本当に再コンパイルするようにだまそうとしています。

新しいプランを生成するために、ストアドプロシージャを削除して再作成しました。

おとり変数を使用して、再コンパイルを強制し、パラメータの盗聴を防止しようとしました:

CREATE PROCEDURE dbo.ViewOpener @SessionGUID uniqueidentifier AS

DECLARE @SessionGUIDbitch uniqueidentifier
SET @SessionGUIDbitch = @SessionGUID

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

ストアドプロシージャの定義も試みましたWITH RECOMPILE

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

計画がキャッシュされないように、実行時に再コンパイルを強制的に試みました:

EXECUTE ViewOpener @SessionGUID WITH RECOMPILE

それは助けにはならなかった。

プロシージャを動的SQLに変換してみました。

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

それは助けにはならなかった。

エンティティ " Report_Opener"はインデックス付けされていないビューです。ビューは基礎となるテーブルのみを参照します。インデックス付きまたはその他の計算列を含むテーブルはありません。

それの地獄のために私はでビューを作成しようとしました

SET ANSI_NULLS ON
SET QUOTED_IDENTIFER ON

それはそれを修正しませんでした。

どうですか

  • クエリは高速です
  • クエリをビューに移動し、ビューからの選択が速い
  • ストアドプロシージャからのビューからの選択は40倍遅くなりますか?

ビューの定義を直接ストアドプロシージャに移動しようとしました(3つのビジネスルールに違反し、重要なカプセル化を解除しています)。

ストアドプロシージャのバージョンが非常に遅いのはなぜですか?別の種類のアドホックSQLよりもアドホックSQLを高速に実行しているSQL Serverを説明できるものは何ですか?

本当にしたくない

  • SQLをコードに埋め込む
  • コードを変更する

    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)

しかし、SQL Serverがクエリを実行しているSQLサーバーほど高速に実行できないことを説明できるのは、パラメータスニッフィングではない場合です。


私の次の試みは、ビューをクエリするためにStoredProcedureAcall StoredProcedureBcall StoredProcedureCcall StoredProcedureDを実行することです。

それが失敗した場合は、ストアドプロシージャでストアドプロシージャを呼び出し、UDFを呼び出し、UDFを呼び出し、ストアドプロシージャを呼び出し、UDFを呼び出してビューをクエリします。


要約すると、以下はQAからは高速に実行されますが、ストアドプロシージャに入れると低速になります。

オリジナル:

--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)

実行計画

良い計画:

      |--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)

悪い計画

       |--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)

悪い方は600万行を積極的にスプールしています。もう1つはそうではありません。

注:これは、クエリの調整に関する問題ではありません。高速で実行されるクエリがあります。SQL Serverをストアドプロシージャから高速に実行したいだけです。


パラメータを取得して別のパラメータに再割り当てし、後でクエリで使用するたびにこれが発生する可能性があります。答えは「不明な@ "someparamname"の最適化」で機能します。
JustDave

回答:


404

元のポスターと同じ問題がありましたが、引用された回答では問題を解決できませんでした。クエリは、ストアドプロシージャからの実行が非常に遅くなっています。

私はここに別の答えを見つけました "Parameter Sniffing "、ありがとうOmnibuzz まとめると、ストアドプロシージャのクエリで「ローカル変数」を使用しますが、理解を深めるためにオリジナルを読んでください。例えば

遅い方法:

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

速い方法:

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

    SELECT * 
    FROM orders
    WHERE customerid = @LocCustID
END

これが誰かを助けることを願って、これを実行すると私の実行時間が5分以上から約6〜7秒に短縮されました。


23
+1しかし、これは非常に奇妙であり、すべての手順でこれを実行する必要があるか、そうでない場合はいつ実行するかなど、多くの質問が生じます。
gotqn 2014年

31
この行動に困惑するのは私だけですか?パラメータの盗聴を防ぐためにローカル変数を宣言する必要がありますか?SQL Serverは、これが最初から起こらないように十分にスマートであるべきではありませんか?これは、Microsoftの近視眼的なデザインであるIMHOによる不要なコード膨張を引き起こすだけです。
l46kok

4
15分-> 8秒!ライフセーバー
トニーブリックス2015

3
@BennettDill WITH RECOMPILEは私にとっては違いがなく、ローカルパラメータのみを変更しました。
強盗屋2017年

8
これは、今クエリヒントを使用して達成することができます- OPTION((@varA UNKNOWN、@varB UNKNOWN)FOR OPTIMIZE
デイブ

131

私は問題を見つけました、これはストアドプロシージャの遅いバージョンと速いバージョンのスクリプトです:

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

違いを見つけられなかったとしても、私はあなたを責めません。違いは、ストアドプロシージャにはまったくありません。高速な0.5コストのクエリを600万行の熱心なスプールを実行するクエリに変える違い:

スロー: SET ANSI_NULLS OFF

速い: SET ANSI_NULLS ON


この回答には、ビューに次のような結合句があるため、理にかなっている場合もあります。

(table.column IS NOT NULL)

したがって、いくつかNULLのが含まれます。


Query Analizerに戻って実行すると、説明がさらに証明されます

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

そして、クエリは遅いです。


したがって、問題、クエリがストアドプロシージャから実行されているためではありません。問題は、Enterprise Managerの接続のデフォルトオプションがQAのデフォルトではANSI_NULLS offなくANSI_NULLS onであるということです。

Microsoftはこの事実をKB296769で認めています(バグ:SQL Enterprise Managerを使用して、リンクサーバーオブジェクトを含むストアドプロシージャを作成することはできません)。回避策はANSI_NULLS、ストアドプロシージャダイアログにオプションを含めることです。

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

2
旋削ANSI_NULLS ONがどのようにしてこのような大きなパフォーマンスの違いをもたらすのか、私はまだ理解していません。
ジャスティンヘルガーソン2013

2
@ Ek0nomikというのはJOIN、ビュー内の句の意味が異なるためANSI_NULLS OFFです。突然行が一致し、オプティマイザがクエリをまったく異なる方法で実行するようになります。すべての行の99.9%を削除するのではなく、突然戻ってきたとします。
Ian Boyd

2
注: ANSI_NULLS OFFは非推奨であり、悪い習慣と見なされています
ジャン

2
リンク "SQL Serverの将来のバージョンでは、ANSI_NULLSは常にONになり、オプションを明示的にOFFに設定するアプリケーションはエラーを生成します。この機能を新しい開発作業で使用することは避け、現在この機能を使用しているアプリケーションを変更することを計画してください。 」
2017

私の場合は役に立ちませんでした。
st_stefanov

19

データベースに対してこれを行います。同じ問題があります-1つのデータベースで正常に機能しますが、このデータベースを(通常の復元ではなく)SSISインポートを使用して別のデータベースにコピーすると、ほとんどのストアドプロシージャでこの問題が発生します。それで、もう少しグーグルで調べた後、Pinal Daveブログを見つけました(彼の投稿のほとんどに出会い、Pinal Daveにとても感謝しました)

私のデータベースで以下のクエリを実行すると、問題が修正されました。

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

お役に立てれば。私を助けてくれた他の人からの助けを単に渡す。


2
将来の読者のための参考までに:DBCC REINDEX非推奨となったので、代替案を探す必要があります。
2015年

1
私の問題を解決しました、ありがとう(1分20秒から2秒に!)。再:DBCC DBREINDEX、MSは言う:「この機能は、Microsoft SQL Serverの将来のバージョンで削除される予定の新しい開発作業ではこの機能を使用すると、現在はすぐに代わりの可能な用途ALTER INDEXなどとして、この機能を使用するアプリケーションを変更しないでください。。。」
AjV Jsy

これが最善の答えかどうかはわかりませんが、私の場合、sp_updatestatsで十分なので、+ 1
Todd Menier

..はい、そして、インデックスの再構築には時間とスペースがかかる可能性があることを忘れないでください。そのため、運用サーバーでこれを実行する前に、可能なスローダウンを許容できることを確認してください。REORGANIZEまたはREBUILD WITH(ONLINE = ON)を検討することをお勧めします
ミラノ

14

私は同じ問題に直面していました&この投稿は私にとって非常に役に立ちましたが、投稿された回答のどれも私の特定の問題を解決しませんでした。私は他の誰かを助けることができることを期待して私のために働いた解決策を投稿したかった。

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

クエリの最後に、OPTION(OPTIMIZE FOR(@now UNKNOWN))を追加します


4

今回は問題を見つけました。次回の運が悪く、それを理解できない場合は、プランのフリーズを使用して、間違った実行プランの心配をやめることができます。


そのブログエントリによると、プランのフリーズはMS SQL 2005以降のみであるため、OPには役立ちません。
コクシー、

問題は、間違ったクエリプランを使用していたことでした。私はそれを間違ったものに凍結したくありません。
Ian Boyd、

4

この問題が発生していました。私のクエリは次のようになりました:

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

私のストアドプロシージャは次のように定義されました。

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

データ型を日付時刻と出来上がりに変更しました!30分から1分に行った!

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

2
A LOT Leeに感謝します、これは私の日を救いました!次に、日時フィールドの日付部分のみを取得する方法を示します。DATEADD(dd、0、DATEDIFF(dd、0、table.field))
ジュリアンB.

1
これで問題が解決しました。私は列varchar(20)を持っていて、パラメータータイプを列タイプと同じにすると、パラメーターはnvarchar(50)になりました-これ以上の遅延はありません。
st_stefanov

3

Report_Openerテーブルの統計やインデックスを再構築してみましたか?データベースが最初に起動されたときからのデータが統計にまだ表示されている場合、SPのすべての再準拠は何の価値もありません。

オプティマイザーはパラメーターが決してnullにならないことがわかるので、最初のクエリ自体はすぐに機能します。SPの場合、オプティマイザーはパラメーターがnullになることは決してありません。


ストアドプロシージャ宣言で、iパラメータをnullにできないことを示す方法はありますか?そして、それはsp_executesqlによって修正されるものではありませんか?
Ian Boyd、

つまり、2000年ではなく、いやです。2005では、パラメーターの値の例を提供できるクエリヒントが追加されました。オプティマイザーは、そのパラメーターが常に使用されることを知っているかのように最適化します。とは言っても、私はこの種のことを統計の問題であると一般に思っています。
AnthonyWJones 2009年

それが統計の問題である場合、アドホック、sp_executesql、exec()を実行すると、QAから正常に機能します。そして、ストアドプロシージャにアドホックSQL、sp_executesql、exec()が含まれていると、なぜそれらすべてがうまく実行されないのですか
Ian Boyd、

1

私は通常は反対しますが(この場合は本当の理由があるようです)、クエリのSPバージョンにクエリヒントを提供しようとしましたか?SQL Serverがこれら2つのインスタンスで異なる実行プランを準備している場合、ヒントを使用して、使用するインデックスを指示し、プランが最初のプランと一致するようにできますか?

いくつかの例については、こちらをご覧ください

編集:ここにクエリプランを投稿できる場合、おそらく私たちが伝えているプラ​​ン間のいくつかの違いを特定できます。

2番目:SQL-2000固有になるようにリンクを更新しました。下にスクロールする必要がありますが、探しているのが「テーブルヒント」というタイトルの2つ目です。

3番目:「悪い」クエリは、「オープナー」テーブルの[IX_Openers_SessionGUID]を無視しているようです-インデックスヒントを追加して、そのインデックスを使用するように強制する可能性はありますか?


そのリファレンスで最も有用なクエリヒントは、ここで問題となっているバージョンであるSQL 2000では利用できません。
AnthonyWJones 2009年

さらに、どのようなヒントが必要ですか?SQL Serverは、アドホックで実行しても問題ないことを理解できます。
Ian Boyd、

もちろん、それはいつも私の経験でもあります。ただし、この場合、まったく異なるexec計画が考えられると彼は言っています。アドホックで使用されているインデックスがあるかもしれませんが、何らかの理由でプロシージャで無視されています。SQL Serverに「INDEX」ヒントを使用してインデックスを使用させることができます。
SqlRyan 2009年

1

これはおそらくありそうにありませんが、観察された動作が異常であることを考えると、確認する必要があり、他の誰もそれを言及していません。

すべてのオブジェクトがdboによって所有されており、自分または別のユーザーが所有する不正なコピーが存在しないことを本当に確信していますか?

たまに奇妙な動作を目にしたのは、実際にはオブジェクトのコピーが2つあり、どちらが取得されるかは、指定されたものと、ログオンしているユーザーによって異なるためです。たとえば、同じ名前で異なる所有者によって所有されているビューまたはプロシージャの2つのコピーを持つことは完全に可能です。dboとしてデータベースにログオンしておらず、dboをオブジェクト所有者として指定し忘れた場合に発生する可能性があります。オブジェクトを作成します。

テキストでは、所有者を指定せずにいくつかを実行していることに注意してください。例:

sp_recompile ViewOpener

たとえば、dboと[他のユーザー]が所有するviewOpenerの2つのコピーが存在する場合、指定しない場合に実際に再コンパイルするのは状況によって異なります。Report_Openerビューを使用した同上-2つのコピーがある場合(およびそれらが仕様または実行プランで異なる可能性がある場合)、使用されるものは状況によって異なります。所有者を指定しないと、アドホッククエリが1つを使用し、コンパイルされたプロシージャは他を使用する場合があります。

私が言っているように、それはおそらくありそうにありませんが、それは可能であり、そしてあなたの問題はあなたが単に間違った場所でバグを探しているということであるかもしれないのでチェックされるべきです。


1

これはばかげているように聞こえ、SessionGUIDという名前からは明らかなようですが、列はReport_Openerの一意の識別子ですか?そうでない場合は、正しい型にキャストして試してみるか、変数を正しい型に宣言してください。

sprocの一部として作成された計画は、直感的に機能せず、大きなテーブルで内部キャストを実行する場合があります。


そうではない。しかし、varchar列とnvarchar値(例WHERE CustomerName = N'zrendall')を比較するwhere句でパフォーマンスの問題が発生しました。SQL Serverはnvarchar、比較前にすべての列の値をに変換する必要がありました。
Ian Boyd

0

別のアイデアがあります。このテーブルベースの関数を作成するとどうなるでしょうか。

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

そして、次のステートメントを使用してそこから選択します(これをSPに配置することもできます)。

SELECT *
FROM tbfSelectFromView(@SessionGUID)

何が起こっているのか(誰もがすでにコメントしているようです)は、SQL Serverが間違った場所で仮定を行っているだけであり、これにより、仮定が修正される可能性があります。余分なステップを追加するのは嫌ですが、他に何が原因であるかはわかりません。


0

-これが解決策です:

create procedure GetOrderForCustomers(@CustID varchar(20))

as

begin

select * from orders

where customerid = ISNULL(@CustID, '')

end

- それでおしまい

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.