2009-10-02 7 views
8

.NETからSQL Serverのsp_executesqlストアドプロシージャへの呼び出しを実行しているORMを使用しています。.NETのコードからSQLクエリが遅いが、対話的ではない

ストアドプロシージャが.NETから呼び出されると、タイムアウト例外が発生します。

プロファイラを見ると、実際にはクエリの実行に長時間かかることがわかります。

クエリは、本質的である:

exec sp_executesql N'SELECT DISTINCT 
FROM [OurDatabase].[dbo].[Contract] [LPLA_1]) [LPA_L1] 
LEFT JOIN [OurDatabase].[dbo].[Customer] [LPA_L2] ON [LPA_L2].[Customer_ID]=[LPA_L1].[CustomerId] AND [LPA_L2].[Data]=[LPA_L1].[Data]) 
WHERE ((((([LPA_L1].[DealerId] = @DealerId1)) 
AND ([LPA_L2].[Last_Name] = @LastName2))))',N'@DealerId1 varchar(18),@LastName2 varchar(25)',@DealerId1='1234',@LastName2='SMITH' 

私にとって紛らわしい部分はこれです:私はコピーして、SQL管理スタジオにタイムアウトのクエリを貼り付け、対話的にそれを実行した場合、それがうまく実行されます。

.NETコードを使用して実行した場合、同じクエリで時間が大幅に長くかかる理由は誰にも分かりますか? (私はこれを再現することができます。コードから一貫してタイムアウトしたクエリは、一貫して対話的に実行されます。ありがとう!

+0

返信するデータの行数はいくつですか?数千、数千の線がある場合、結果を期待してコンピュータにワイヤを押し込むのに時間がかかる可能性があります。 – Miles

+0

クエリで多くのデータが返されますか?インタラクティブモードでは発生しない、プログラムケースに関係するサーバとクライアントとの間で送信されるデータはありますか? – quosoo

+0

3つのテストケース。さらに、DealerIDとLast_Nameにはインデックスがあります。 –

答えて

0

dealerIdまたはLastname nvarchar(varcharパラメータとは異なるタイプ)ですか?

これは、インデックス全体の変換を引き起こす可能性があります。これが当てはまる場合は、コメントを残してください。私はより詳細に説明します。

+0

いいえ、どちらもデータベース内のvarcarsですが、残念なことに –

4

インデックスフィールドのクエリパラメータのnvarchar型とvarchar型の不一致がある場合は、数回見たことがあります。これは、データベースでvarcharを使用し、明示的に.Netでパラメータのタイプを設定しないと発生する可能性があります。デフォルトではnvarcharとみなされます。

この場合、Sql Serverはパフォーマンスの良いオプションではなく正しいオプションを選択します。パラメータをvarcharに変換するのではなく、情報が失われる可能性のある変換が狭くなると、データベース内のその列のすべての値がnvarcharに変換されます(情報の損失なしで成功することが保証されます) 。それは遅いだけでなく、SQL Serverはもうインデックスを使用できなくなります。言うまでもなく、クエリの実行にはかなり時間がかかります。

+0

SQL Mgmt Studioではなく.NETからクエリを実行するのはなぜ重要ですか? –

+0

あなたは私のポストを読んだ? .NETでsqlcommandオブジェクトのパラメータを作成するとき(たとえその部分がormによって隠されていても)、それらのパラメータのタイプが何であるかを明示的に知らせないと、.Netがあなたのために選択し、間違って選択する可能性があります。その結果、まったく同じクエリではありません。 –

+0

はい、AlexWalkerはSQL Mgmt Studioでプロファイラから取得したクエリ==>を実行しています。これは、オリジネータ(.NETまたはMgmt。Studio)に関係なく、SQL Serverが最終的に実行するクエリとまったく同じです。 接続が異なって構成されていない限り...私は、接続が違いを生み出すものであるという勘違いがあります。 –

1

私は同じ問題があります。手続きは.netから実行され、時間がかかりすぎて(多くの行が返されません)。私はsqlに文字列を送ります: "stored_procedure @ parameter1 = value1"を実行し、これをコピーしてSQL管理スタジオで実行しますが、すべて正常に動作します。このケースの厄介なのは、私のクエリでは、それを引き起こすパラメータ値からLETTERを追加または削除するだけです。私は非常に混乱しています。

私は全文索引と一時表を使用していますが、私が言ったように、SAME QUERY(と私は確信しています)はSQL管理スタジオで完璧に動作します。

1

ちょうど同じ問題がありました。

インデックスを再構築すると問題が解決しました。

多分問題は、varchar列にあるnvarcharとインデックスの間のパラメータの型にあります。

1

sp_executelsqlはコンパイルされたクエリプランを再利用するためのものだと思います。同じクエリが再びヒットしたときにパラメータを再スニッフィングしないため、非常に遅いプランを使用することになります現在のパラメータ値でクエリプランが遅くなる理由を教えてください)。sp_executesqlがインデックスを選択するために別の方法を使用するように見えます。明らかに、プレーンテキストクエリと比較して壊れたメソッドです。

sp_executesqlがネストされたループのチェーンを介してフィードされているときに、 'Company(a table)'のテーブル更新が異なるのは、テキストクエリが一連のハッシュマッチで供給されている間です。ビューの構築は、2つのバージョン(私が期待する)の間で同じように見えます。残念ながら、残りの部分は非常に複雑で、途中で根本的に異なることをしているように見えます。 「実際の」実行プランを取得しても、クエリのさまざまなサブコンポーネントの実際の実行時間は得られません。本当に、私はsp_executesqlが何か異なったものを選択する理由を見ることができませんが、かなり遅い計画を確実に構築します。

パラメータスニッフィングはこれに対する解決策ですので、パラメータ名の名前を変更するか、sp_executesqlが古いスロープランを使用する代わりにクエリプランを再作成する原因となるwhere句の列名をスワップすることもできます。解決策ではありませんが、それほど遅い計画をキャッシュしません。

よろしくお願いいたします。

+0

ありがとう、これは本当のように見えます –

1

ここに私が見つけたものがあります。私は非常に複雑なストアドプロシージャを持っているので、常に情報を数え、毎月Crystal Reportsによって呼び出され/実行されるので、データを8列17行の行列に入れます。 prodデータベースは、96 GBのクレイジーな高速サーバー上にありました!最近、32 GBの仮想マシンに縮小されました。スケールダウンしている間、いくつかのインデックスが追加されるまで、アプリはさまざまな方法で低速で実行されました。

そして、この17行行列の月次レポートを実行するようになったのです。あなたが想像しているように、タイムアウトしました!

proc呼び出しは3つのパラメータで非常に簡単でした。開始日、終了日、およびフィルタリングする地区 - すべてがNULLに等しい。 2つの日付はCrystal Reportsから文字として渡され、このストアドPROCパラメータは、この狂ったストアドプロシージャのいたるところで使用されました。

各17行は、基本的にはWITH文とクレイジージョインを使用してデータの行を検索し、結果にピボットします。この記事では重要ではありません。

だからここにそれが簡略化されている....

CREATE PROCEDURE [dbo].[prcMonthlyStats] 
@bDate   datetime 
,@eDate   datetime 
,@districtStr varchar(120) 
AS 
BEGIN 
SET NOCOUNT ON; 

...

--the @bDate and @eDate params were DIRECTLY used throughout the 2000 lines of SQL, 
--to filter data inside and out of WITH statements and various other selects! 
-- 
--TIMES OUT! 

...

は物語の道徳的なので、ある

CREATE PROCEDURE [dbo].[prcMonthlyStats] 
@bDateStr  datetime 
,@eDateStr  datetime 
,@districtStr varchar(120) 
AS 
BEGIN 
SET NOCOUNT ON; 

--FIX! Declare 2 date time variables and simply assign the 2 date time parameters to them. 
DECLARE @bDate  datetime 
DECLARE @eDate  datetime 
DECLARE @district varchar(120) 

--SET THE VARIABLES FROM THE PARAMETERS PASSED IN! 
SET @bDate = @bDateStr 
SET @eDate = @eDateStr 
SET @district = @districtStr 
..... 

--PRESTO! The optimizer could once again use indexes as it should. 

- オプティマイザでしたDECLAREDのdatetimesを使ってそのことを行うことができます。