Запрос адаптера таблицы выдает ошибку, которая не воспроизводится в SQL Server Management Studio - PullRequest
0 голосов
/ 17 сентября 2010

Я поддерживаю некоторые запросы, определенные в конструкторе адаптеров таблиц в Visual Studio, который используется в некоторых отчетах в приложении Windows Forms (.NET 2.0).Когда я запускаю приложение и выполняю определенный запрос, я получаю сообщение об ошибке: Ошибка арифметического переполнения при преобразовании выражения в тип данных 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 issmallmoney не нуль.Поле «Всего» в таблице данных сопоставлено с «System.Decimal».Я мог бы попытаться преобразовать smallmoney в деньги в выражении, но зачем мне это делать, если в SQL Studio все работает нормально?

Исключение, которое я получаю: Тип исключения: System.Data.SqlClient.SqlException Сообщение об исключении: Ошибка арифметического переполнения при преобразовании выражения в тип данных smallmoney.

   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

Новые проблемы.Теперь проблема с кастингом маленьких денег исчезла, но теперь у меня проблема с тайм-аутом.Другой запрос, используемый в том же отчете, выполняется в течение 5-6 секунд, если выполняется в SSMS.При запуске в настольном адаптере время ожидания истекает через 10 минут.Другие запросы выполняются, как и ожидалось, с тем же результатом, что и в SSMS.Это поддерживает моё подозрение, что что-то гнилое происходит, когда мой адаптер таблицы пытается запросить базу данных.

Обновление 3

Это начинает становиться странным.Запрос проблемы smallmoney был заполнен запросом номер пять в серии запросов, использованных для генерации отчета.После того, как я применил исправление, упомянутое в первом обновлении, я получаю тайм-ауты в первом из запросов.Этот запрос выполнялся без проблем, когда 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.Если я расширяю интервал дат до периода, когда запрос smallmoney также не выполнялся, я получаю тайм-аут.Как я могу получить тайм-аут в запросе, который выполняется ДО запроса smallmoney, если он работает нормально, когда запрос smallmoney не выполняется?Выполнение всех запросов в SSMS работает как положено.Кстати, запросы выполняются синхронно.

Ответы [ 3 ]

1 голос
/ 17 сентября 2010

Можете ли вы посмотреть на планы выполнения для обоих? (Извлекается из ниже)

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 будут записаны данные, которые впоследствии будут отфильтрованы?

0 голосов
/ 17 сентября 2010

Стоит проверить, позволяет ли изменение свойств сеанса для SSMS соответствовать свойствам вашего соединения .net, повторить ошибку.

В частности, стоит посмотреть ARITHABORT, который я виделвызывают проблемы, аналогичные тем, которые вы описали в прошлом.По умолчанию, я полагаю, что соединения SSMS устанавливают arithabort, тогда как .net отключает его.

Вы можете изменить свойство в SSMS с помощью команды SET ARITHABORT [ ON | OFF].Возможно, вам придется проверить трассировку профилировщика, чтобы подтвердить настройки в среде .Net.

0 голосов
/ 17 сентября 2010

В запросе пытались ли вы привести значения к ДЕНЬГАМ?

Что-то вроде

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