0

Windows フォーム アプリケーション (.NET 2.0) の一部のレポートで使用される Visual Studio のテーブル アダプター デザイナーで定義されたいくつかのクエリを維持しています。アプリケーションを実行して特定のクエリを実行すると、次のエラーが表示されます。式をデータ型 smallmoney に変換すると、算術オーバーフロー エラーが発生します。クエリはかなり少量を生成するはずなので、私は驚いたので、SQL プロファイラーでクエリをキャプチャし、SQL Server Management Studio で (明らかに同じデータベースで) まったく同じクエリを実行しました。ここで、クエリは問題なく実行され、smallmoney は "33.00" です。214,748.3647 境界のどこにもありません。

デバッグを複雑にするために、この問題はクライアントの QA 環境でのみ発生し、ローカルでは再現できません (また、法的な理由により、データベースを開発環境にコピーすることはできません)。これにより、クライアントの環境で新しいバージョンをビルドして展開するのに最大 30 分かかるため、デバッグ サイクルが非常に遅くなります。そのため、できるだけ少ない実験でこの問題を特定するためのヒントをいただければ幸いです。SQL Studio でクエリをいじっても、同じエラーを発生させることはできないため、あまり役に立ちません。

クエリは次のとおりです。

SELECT        CONVERT(varchar, Events.Occurred, 102) AS Day, Users.Name, COUNT(*) AS Deleted_Invoices, SUM(i.TotalExVat + i.TotalVat) AS Total
FROM            Events WITH (nolock) INNER JOIN
                         Users WITH (nolock) ON Events.UserID = Users.UserID INNER JOIN
                         Types AS t WITH (nolock) ON t.TypeID = Events.TypeID INNER JOIN
                         InvoicesEvents AS ie ON ie.EventID = Events.EventID INNER JOIN
                         Invoices AS i ON i.InvoiceID = ie.InvoiceID
WHERE        (Events.Occurred BETWEEN @startDate AND @endDate) AND (t.Name = 'InvoiceDeleted')
GROUP BY CONVERT(varchar, Events.Occurred, 102), Users.Name
ORDER BY Day, Users.Name

TotalExVat および TotalVat は smallmoney ではありません。データ テーブルの「Total」フィールドは、「System.Decimal」にマップされます。式で smallmoney を money にキャストすることもできますが、SQL スタジオで正常に実行されるのに、なぜそれを行う必要があるのでしょうか?

私が取得する例外は次のとおりです。

   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
   at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
   at System.Data.SqlClient.SqlDataReader.HasMoreRows()
   at System.Data.SqlClient.SqlDataReader.ReadInternal(Boolean setTimeout)
   at System.Data.SqlClient.SqlDataReader.Read()
   at System.Data.Common.DataAdapter.FillLoadDataRow(SchemaMapping mapping)
   at System.Data.Common.DataAdapter.FillFromReader(DataSet dataset, DataTable datatable, String srcTable, DataReaderContainer dataReader, Int32 startRecord, Int32 maxRecords, DataColumn parentChapterColumn, Object parentChapterValue)
   at System.Data.Common.DataAdapter.Fill(DataTable[] dataTables, IDataReader dataReader, Int32 startRecord, Int32 maxRecords)
   at System.Data.Common.DbDataAdapter.FillInternal(DataSet dataset, DataTable[] datatables, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior)
   at System.Data.Common.DbDataAdapter.Fill(DataTable[] dataTables, Int32 startRecord, Int32 maxRecords, IDbCommand command, CommandBehavior behavior)
   at System.Data.Common.DbDataAdapter.Fill(DataTable dataTable)
   at ... (calling code)

アップデート

SUM(i.TotalExVat + i.TotalVat) を SUM(i.TotalExVat) + SUM(i.TotalVat) に変更するとエラーが解消されましたが、生成された結果に小さなお金のオーバーフローがないため、その理由はまだわかりません。

更新 2

新しい問題。スモールマネーのキャスティングの問題はなくなりましたが、タイムアウトの問題が発生しました。同じレポートで使用される別のクエリは、SSMS で実行した場合、約 5 ~ 6 秒で実行されます。テーブル アダプタで実行すると、10 分後にタイムアウトします。他のクエリは期待どおりに実行され、SSMS と同じ結果が生成されます。これは、テーブル アダプターがデータベースにクエリを実行しようとすると、何かがおかしいという私の疑いを裏付けるものです。

アップデート 3

これは奇妙になり始めています。小額問題のクエリは、レポートを生成するために使用される一連のクエリの 5 番目のクエリを埋めます。最初の更新に記載されている修正を適用した後、最初のクエリでタイムアウトが発生します。後のクエリで smallmoney がオーバーフローしていたとき、そのクエリは問題なく実行されました。その理由は何でしょうか?

smallmoney クエリでエラーが発生したときに実行され、動作しているときに実行されていないクエリ:

SELECT        u.Name AS Username, rea.Text AS DeleteReason, COUNT(*) AS DeletedRegistrations, SUM(r.Shipments) AS DeletedShipments
FROM            RecordingsEvents AS re WITH (nolock) INNER JOIN
                         Events AS e WITH (nolock) ON e.EventID = re.EventID INNER JOIN
                         Reasons AS rea WITH (nolock) ON rea.ReasonID = e.ReasonID INNER JOIN
                         Users AS u WITH (nolock) ON u.UserID = e.UserID INNER JOIN
                         Recordings AS r ON r.RecordingID = re.RecordingID
WHERE        (rea.Category = 'DeleteRecording') AND (e.Occurred BETWEEN @startDate AND @endDate)
GROUP BY u.Name, rea.Text
ORDER BY Username, MAX(rea.SortOrder)

smallmoney クエリの結果が 30.0.0.0 である日付間隔を制限すると、上記のクエリは機能します。smallmoney クエリも失敗していた期間に日付間隔を拡張すると、タイムアウトが発生します。smallmoney クエリが失敗したときに正常に実行されたときに、smallmoney クエリの前に実行されるクエリでタイムアウトを取得するにはどうすればよいですか? SSMS ですべてのクエリを実行すると、期待どおりに動作します。ところで、クエリは同期的に実行されます。

4

3 に答える 3

1

両方の実行計画を確認できますか? (以下から取得可能)

SELECT usecounts, cacheobjtype, objtype, text, query_plan, value as set_options
FROM sys.dm_exec_cached_plans 
CROSS APPLY sys.dm_exec_sql_text(plan_handle) 
CROSS APPLY sys.dm_exec_query_plan(plan_handle) 
cross APPLY sys.dm_exec_plan_attributes(plan_handle) AS epa
where text like '%SELECT        CONVERT(varchar, Events.Occurred, 102) AS Day, Users.Name, COUNT(*) AS Deleted_Invoices, SUM(i.TotalExVat + i.TotalVat) AS Total%' and attribute='set_options'

SUMSそのうちの 1 つが、後でフィルター処理されてしまうレコードを作成する計画になってしまうのではないかと思います。

于 2010-09-17T10:01:34.993 に答える
0

クエリで、値をMONEYにキャストしようとしましたか?

何かのようなもの

SUM(CAST(i.TotalExVat AS MONEY) + CAST(i.TotalVat AS MONEY))

加算が発生すると、値は同じタイプに保持されるように見えるため、オーバーフローがあるとそれが壊れます。

SMALLMONEYは、使用するのに非常に小さいタイプのように見えます。

この例を見てください

DECLARE @table TABLE(
        Value SMALLMONEY
)

INSERT INTO @table SELECT 200000
INSERT INTO @table SELECT 200000
INSERT INTO @table SELECT 200000
INSERT INTO @table SELECT 200000

--IS FINE
SELECT SUM(CAST(Value AS MONEY) + CAST(Value AS MONEY))
FROm    @table

--BREAKS
SELECT SUM(Value + Value)
FROm    @table
于 2010-09-17T09:22:31.340 に答える
0

SSMS のセッション プロパティを .net 接続のセッション プロパティと一致するように変更すると、エラーを再現できるかどうかを確認する価値があります。

特に、ARITHABORTあなたが過去に説明したものと同様の問題を引き起こしているのを見たことがあります。デフォルトでは、SSMS接続はarithabortをオンに設定し、.netはそれをオフに設定すると思います。

コマンドを使用して、SSMS のプロパティを変更できますSET ARITHABORT [ ON | OFF]。.Net 環境での設定を確認するには、プロファイラー トレースを調べる必要がある場合があります。

于 2010-09-17T09:24:37.840 に答える