2009-05-19 30 views
4

私は常には単一のintを返すべきクエリを持っています。私は今、それがなければならないものとは全く関係のない文字列を返すようにログに記録しました。intでなければならないSqlCommandが文字列を返すのはなぜですか?

いくつかのデータベースクエリまで追跡したいくつかのランダムなFormatExceptionsがあります。追加のロギングの後、私は、今朝、以下のクエリで文字列 "gladiator"が返されたことがわかりました。 Website.PkIDはint型のカラムで、ほとんどの場合動作しますが、失敗すると失敗し、そこからwaaaay(有効なWebsiteIDより大きい)またはランダムな文字列を返します。

この特定のクエリは、セッション開始ごとに1回ヒットします。共有接続を使用していないため、このような混乱した結果をどうやって得ることができるか理解できません。接続プールに何らかの破損がありますか?

私は問題がこのクエリに分離されているとは思わない。私は同様のFormatExceptions(予期しない結果のため)LINQクエリから来て同様に見てきました。同じ時間にこれらのエラーのいくつかを検出しました:

A transport-level error has occurred when sending the request to the server. (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.

接続に問題がありますか?あるいは、dbサーバーとWebサーバーの間に結果セットが混在している可能性がありますか?これは本当に私の頭を傷つけてしまった。

問題のクエリ:

public static int GetActiveWebSiteID(string storeID, string statusID) 
{ 
    int retval; 

    string sql = @"SELECT isnull(MAX(PkID),0) FROM WebSite 
        WHERE StoreID = @StoreID 
        AND WebSiteStatusID = @WebSiteStatusID"; 

    SqlConnection conn = new SqlConnection(Settings.ConnString); 
    SqlCommand cmd = new SqlCommand(sql, conn); 
    cmd.CommandType = CommandType.Text; 
    cmd.Parameters.AddWithValue("@StoreID", (object)storeID ?? DBNull.Value); 
    cmd.Parameters.AddWithValue("@WebSiteStatusID", (object)statusID ?? DBNull.Value); 

    conn.Open(); 
    using(conn) 
    { 
     var scalar = cmd.ExecuteScalar(); // <-- This value returned here should only ever be an int, but randomly is a string 

     retval = Convert.ToInt32(scalar); 
    } 
    return retval; 
} 

上記のクエリは、最近まで年間、うまく働いています。私たちは今、アプリケーションにたくさんのLINQクエリを追加しています(違いがあるかどうかはわかりません)。私たちは.Net 3.5を実行しています。

+0

文字列のときの 'スカラー'の値は? –

+0

"0" MAX(PkID)がnullのとき文字列である可能性があります – TheVillageIdiot

+0

前述のように、私が見た文字列は "剣闘士"でした。私は、これは何らかの形で、システムのどこかからの他のクエリ結果、具体的にはキーワード検索と混乱しています。しかし、私はまだそれを証明することはできません。 –

答えて

9

を助け、それが徐々に増加トラフィックとしてクリティカルマスに到達するために始めました。私たちはロギングを増やし、重い負荷のもとで全く異なる結果セットが無関係のクエリに返される数多くの決定的なインスタンスを見つけました。

Profilerでクエリを監視し、悪い結果が常に同じspidに関連付けられていて、それぞれの悪い結果が実際のSQL文のクエリの後ろに1つのクエリであることがわかりました。それは結果セットが見逃されたようなもので、spid(同じプール内の別の接続から)の次の結果セットが返されたようでした。クレイジー。

試行錯誤の結果、SqlConnectionが使用直後に閉じられていないSqlCommandまたはLINQクエリがいくつか見つかってしまいました。代わりに、LINQ接続の誤解に由来するいくつかのちょっとしたプログラミングを通して、DataContextオブジェクトは即座にではなく要求の最後にのみ廃棄され(接続が閉じられました)。

これらのメソッドをリファクタリングして、C# "using"ブロック(次のリクエストでそのプールを解放する)ですぐに接続を閉じると、エラーはなくなりました。接続プールが混乱する根本的な理由はまだ分かっていませんが、このタイプのエラーはすべて終了できました。この問題は、私が投稿した別の同様のエラーと一緒に解決されました:What Causes "Internal Connection Fatal Errors"?

1

ExecuteScalar()関数の戻り値の型はobjectであり、結果変数はvarキーワードで宣言します。これは実際には良い組み合わせではありません。タイプの推論を正しく行うためにシステムに多くのプレッシャーをかけているからです。

public override object ExecuteScalar() 
Member of System.Data.SqlClient.SqlCommand 

概要:

+0

列はintで、結果は "剣闘士"の文字列です。タイプ推論にはこれと何か関係がありません。 int列またはその集約は決して文字列を返すべきではありません。 –

+2

タイプ推論は決して「剣闘士」を生み出すべきではありません:) – VVS

+2

PkIDが実際にはint列でない限り、コードは彼が投稿してはいけません。 –

1

私はあなたがについてsqlCommand.ExecuteNonQuery int値以内影響を受けた行数を返すことを考えていたと思いますが...

これは、ExecuteScalarメソッドの定義です

クエリを実行し、は、クエリによって返された結果セットの最初の行の最初の列を返します。追加の列または行は無視されます。

戻り値:

結果セット内の最初の行の最初の列、または結果セットが空の場合はnull参照(Visual BasicではNothing)。

私は、その列を返す一般的な方法は列の値の文字列表現であると考えています。

+0

ExecuteScalar()は私の望むものです。私は行の数を気にしません。 –

0

フィールド「PkID」は、「WebSite」テーブルのvarchar/charです。

クエリの「ISNULL」の部分がtrueの場合、それは(0)、そうでなければ「のPkID」

+0

質問に記載されているように、Website.PkIDはint列です。 –

0

がある可能性があり、複数のウェブサイトのテーブルの値を持つ文字列を返します整数を返します。 。 StoreID = @StoreID AND WebSiteStatusID = @WebSiteStatusID

+0

Webサイトテーブルは1つだけです。 –

0

がときに何らかの共通性がありますYourSchema.WebSite FROM(0、MAX(のPkID))

SELECT ISNULL:あなたは、スキーマ名でテーブルを修飾することができますintを返さない?あなたのクエリが唯一のこれまで一列に単一列を返すので

、あなたはより多くのタイプセーフなのExecuteReaderを使用し、最初の列の値を取る場合、あなたは何を得るのですか?

は、それが常に列を返しますか? WHERE句によって行が返されない場合(つまり、あなたのパラメータは自分のものとは思われません)、ISNULLは有効にならず、行が全くなく、ExecuteScalarはNULLを返すことになっています。

+0

上記の例では、簡潔にするためにいくつかのコードを削除しました。実際のコードにはより多くのロギングがあり、intへの変換を試みる前にnullとDbNullの "スカラー"の値もチェックします。これらのチェックは結果のないケースを処理します。 –

+0

しかし、あなたがお勧めするように、私はそれが役立つかどうかを確認するためにクエリを再加工しようとします –

1

私は最近、コードが予期せず接続文字列を切り替えたケースを見てきました。診断目的のために、接続文字列をハードコードし、問題がなくなるかどうか確認してください。それはだそれは2つのデータベース・インスタンスがある見つけるために、私は驚かないだろう、と1で、のPkIDは別で、intで

using(SqlConnection conn = new SqlConnection("hard-coded connection string")) 
{ 
    using (SqlCommand cmd = new SqlCommand(sql, conn)) 
    { 
     // more init 
     object scalar = cmd.ExecuteScalar(); 

     // process result 
    } 
} 

:また、正気のために、使用してくださいのようなブロックを使用して、ネストされた

varchar。


"剣闘士"の復帰を捕まえることができるかどうかを調べるには、SQLプロファイラを参照してください。私が働いていた他のケースでは、SQLプロファイラは実際のクエリは、別のデータベースに起こっていたことを示す、全く何も示しませんでした。

+0

そこにウェブサイトテーブルを持つ有効なデータベースは1つだけです。使用方法を少しきれいにすることをお勧めします。 –

+0

プロファイラを使用して「剣闘士」を返したコールを見たことがあるので、これを知っていると思いますか? –

0

私はあなたの投稿クエリでもLINQでもないと思うが問題です。

は、あなたが右のソースを見ているあなたは本当によろしいですか?メソッドはどのように呼び出されますか?ロギングはどのように行われますか?

Select isn't broken.

+0

はい、正しいソースです。上記のサンプルコードでlog4netのログを取り除き、入力と出力を教えてくれた非常に具体的なログを注入しました。 私は、SQL ServerとWebサーバーの間に何らかの種類のネットワークが存在する可能性があることを察知しています。この重大さは決してありませんが、私たちは前に変わった問題を抱えていました。 –

+0

あなたは私を信じていません。 SQLプロファイラを使用して、コードが実行されると予想されるサーバー上で実際に実行されていることを確認すると、実行中のサーバーがわかります。それまでは、あなたは推測しています。 –

0

私はそのSettings.ConnStringが他の静的ルーチンをWeb.Configのか、レジストリから読み込まれ、再利用されると仮定しています。接続上でcmd.CommandTextを変更するルーチンでcmd.ExecuteScalar()を呼び出す前に2番目のメソッドが実行されるタイミングの問題がある可能性はありますか?

希望、これは、この問題を無視して数ヶ月後、

ビル

関連する問題