私はわかりません。私はntextフィールドに格納されたレポートの束とSQLテーブルを持っています。そのうちの1つの値をコピーしてメモ帳に貼り付けて保存したとき(Visual Studioを使用して別の行の小さなレポートから値を取得)、raw txtファイルは約5Mbでした。 SqlDataReaderを使ってこの同じデータを取得しようとすると、それを文字列に変換すると、メモリ不足例外が発生します。ここで私はそれをやろうとしています方法です:SqlDataReaderから文字列を読み取っているときにメモリが不足しています
string output = "";
string cmdtext = "SELECT ReportData FROM Reporting_Compiled WHERE CompiledReportTimeID = @CompiledReportTimeID";
SqlCommand cmd = new SqlCommand(cmdtext, conn);
cmd.Parameters.Add(new SqlParameter("CompiledReportTimeID", CompiledReportTimeID));
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
output = reader.GetString(0); // <--- exception happens here
}
reader.Close();
私は、オブジェクトとデータをつかむためのStringBuilderを作成しようとしたが、私はまだメモリ例外の同じアウトを取得します。私もreader.GetValue(0).ToString()を使用して、無駄にしようとしました。クエリは1行しか返しません。SQL Management Studioで実行すると、その幸せなことができます。
System.OutOfMemoryException was unhandled by user code
Message=Exception of type 'System.OutOfMemoryException' was thrown.
Source=mscorlib
StackTrace:
at System.String.CreateStringFromEncoding(Byte* bytes, Int32 byteLength, Encoding encoding)
at System.Text.UnicodeEncoding.GetString(Byte[] bytes, Int32 index, Int32 count)
at System.Data.SqlClient.TdsParserStateObject.ReadString(Int32 length)
at System.Data.SqlClient.TdsParser.ReadSqlStringValue(SqlBuffer value, Byte type, Int32 length, Encoding encoding, Boolean isPlp, TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParser.ReadSqlValue(SqlBuffer value, SqlMetaDataPriv md, Int32 length, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlDataReader.ReadColumnData()
at System.Data.SqlClient.SqlDataReader.ReadColumn(Int32 i, Boolean setTimeout)
at System.Data.SqlClient.SqlDataReader.GetString(Int32 i)
at Reporting.Web.Services.InventoryService.GetPrecompiledReportingData(DateTime ReportTime, String ReportType) in C:\Projects\Reporting\Reporting.Web\Services\InventoryService.svc.cs:line 3244
at SyncInvokeGetPrecompiledReportingData(Object , Object[] , Object[])
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
InnerException:
null
私は仕事に登場し、他の行番号でテストしていたが、それは、これらのテストIDの偽陽性であったデータを全く持っていなかっ:
スローされた例外はあります。私は、近くにあるレポートを含むテーブルを見て、いくつかの他のテストIDを取得しましたが、同じ例外があります。多分その文字列がどのようにコード化されているのでしょうか?テーブルに格納されているデータは、JSONエンコードされた文字列であり、実際には他の場所で作成したクラスから生成されています。ここ
上記のコードブロックである:
// get the report time ID
int CompiledReportTimeTypeID = CompiledReportTypeIDs[ReportType];
int CompiledReportTimeID = -1;
cmdtext = "SELECT CompiledReportTimeID FROM Reporting_CompiledReportTime WHERE CompiledReportTimeTypeID = @CompiledReportTimeTypeID AND CompiledReportTime = @ReportTime";
cmd = new SqlCommand(cmdtext, conn);
cmd.Parameters.Add(new SqlParameter("CompiledReportTimeTypeID", CompiledReportTimeTypeID));
cmd.Parameters.Add(new SqlParameter("ReportTime", ReportTime));
reader = cmd.ExecuteReader();
while (reader.Read())
{
CompiledReportTimeID = Convert.ToInt32(reader.GetValue(0));
}
reader.Close();
CompiledReportTypeIDs方法の開始時にFRBの文字列パラメータに基づいて正しいCompiledReportTimeTypeIDを取得した辞書です。 ReportTimeは、以前に入力されたDateTimeです。
編集: SQLデータ型の問題を排除するために、テーブルを削除し、ntextの代わりにReportDataフィールドをnvarchar(MAX)として再作成します。それはロングショットなので、私が見つけたものをもう一度更新します。
Edit2: テーブルのフィールドをnvarchar(max)に変更しても効果はありません。私はまた、output = cmd.ExecuteScalar()。ToString()も同様に影響を与えずに使ってみました。私はSqlDataReaderの最大サイズがあるかどうかを調べようとしています。 SQL Mgmt Studioからテキストの値をコピーしたとき、メモ帳に保存されたのはわずか43Kbでした。これを確認するには、既知の作業ID(小さいレポート)のレポートを取り出し、Visual Studioから値をそのままコピーしてメモ帳にダンプしたところ、約5MBでした!つまり、これらの大きなレポートはおそらくnvarchar(最大)フィールドに〜20MBの範囲内にあることを意味します。
Edit3: 私は、devのIISサーバー、SQLサーバー、および私の開発者のラップトップを含めるために、すべてを再起動しました。今それは働いているようです。なぜこれが起こったのか、これは答えではありません。私は何が起こったかについての説明のためにこの質問を開いたままにしておき、そのうちの1つを答えとしてマークします。
Edit4: これは言いましたが、私は事を変更せずに別のテストを実行しましたが、同じ例外が戻ってきました。私はこれがSQLの問題だと思っています。私はこの質問のタグを更新しています。私はまったく同じクエリを実行し、それは正常に動作する別のアプリを作った。
Edit5: 以下の回答のうちの1つに従って順次アクセスを実装しました。すべてがストリームに正しく読み込まれますが、文字列に書き出す際にはメモリ不足例外が発生しています。これは、連続したメモリブロックを取得する問題を示していますか?ここで私はバッファリングを実装する方法である:
reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess);
long startIndex = 0;
long retval = 0;
int bufferSize = 100;
byte[] buffer = new byte[bufferSize];
MemoryStream stream = new MemoryStream();
BinaryWriter writer = new BinaryWriter(stream);
while (reader.Read())
{
// Reset the starting byte for the new CLOB.
startIndex = 0;
// Read bytes into buffer[] and retain the number of bytes returned.
retval = reader.GetBytes(0, startIndex, buffer, 0, bufferSize);
// Continue while there are bytes beyond the size of the buffer.
while (retval == bufferSize)
{
writer.Write(buffer);
writer.Flush();
// Reposition start index to end of last buffer and fill buffer.
startIndex += bufferSize;
retval = reader.GetBytes(0, startIndex, buffer, 0, bufferSize);
}
//output = reader.GetString(0);
}
reader.Close();
stream.Position = 0L;
StreamReader sr = new StreamReader(stream);
output = sr.ReadToEnd(); <---- Exception happens here
//output = new string(buffer);
Edit6: OOM例外が、私は(実行されているメソッドを保持している)IISワーカープロセスは、ほぼ700メガバイトを打つ見る起こると、これに追加するには。これはIIS Expressでは実行されており、本番サーバー上の完全なIISでは実行されません。これはそれと関係がありますか?また、私はByte [] data = stream.ToArray()を呼び出すときに断続的にOOMを取得します。私は本当に必要なのは、このプロセスにもっと多くのメモリを与える方法だと思いますが、どこで設定するのか分かりません。
Edit7: 私のローカルマシン上のIIS Expressを組み込みのVisual Studio Webサーバーに使用することから、私の開発サーバーを変更しました。今OOM例外はなくなりました。私は実際にそれがメモリ問題の連続的なブロックを割り当てていたと思うし、何か理由でIIS Expressはそれをフォークしないだろうと思う。今は正常に動作していますので、2008R2の全面的なサーバーに公開して、通常のIIS7を実行して、その動作を確認します。
完全なエラーメッセージも含めてください。 –
返される文字列の大きさはどれくらいですか?言い換えれば、ReportDataの大きさはどれくらいですか? –
例外の完全なスタックトレースを表示します。 –