На первый взгляд предпочтительный подход
У меня сложилось впечатление, что следующее уже было проверено другими, особенно на основе некоторых комментариев. Но мое тестирование показывает, что эти два метода действительно работают на уровне БД, даже при подключении через .NET SqlClient
. Они были проверены и проверены другими.
Сервера
Вы можете установить настройку конфигурации сервера пользовательских опций так, чтобы она была битовой OR
с 64 (значение для ARITHABORT
). Если вы не используете побитовое ИЛИ ( |
), а вместо этого делаете прямое присваивание ( =
), тогда вы уничтожите любые другие существующие опции, которые уже включены.
DECLARE @Value INT;
SELECT @Value = CONVERT(INT, [value_in_use]) --[config_value] | 64
FROM sys.configurations sc
WHERE sc.[name] = N'user options';
IF ((@Value & 64) <> 64)
BEGIN
PRINT 'Enabling ARITHABORT...';
SET @Value = (@Value | 64);
EXEC sp_configure N'user options', @Value;
RECONFIGURE;
END;
EXEC sp_configure N'user options'; -- verify current state
База данных уровня
Это может быть установлено для каждой базы данных через ALTER DATABASE SET :
USE [master];
IF (EXISTS(
SELECT *
FROM sys.databases db
WHERE db.[name] = N'{database_name}'
AND db.[is_arithabort_on] = 0
))
BEGIN
PRINT 'Enabling ARITHABORT...';
ALTER DATABASE [{database_name}] SET ARITHABORT ON WITH NO_WAIT;
END;
Альтернативные подходы
Плохая новость заключается в том, что я много занимался поиском по этой теме, но обнаружил, что в течение многих лет многие другие занимались поиском по этой теме, и нет способа настроить поведение. из SqlClient
. Некоторая документация MSDN подразумевает, что это может быть сделано через ConnectionString, но нет ключевых слов, которые позволили бы изменить эти настройки. Другой документ подразумевает, что его можно изменить с помощью Client Network Configuration / Configuration Manager, но это также не представляется возможным. Следовательно, и, к сожалению, вам нужно будет выполнить SET ARITHABORT ON;
вручную. Вот несколько способов рассмотреть:
Если вы используете Entity Framework 6 (или новее), вы можете попробовать:
Использовать Database.ExecuteSqlCommand : в context.Database.ExecuteSqlCommand("SET ARITHABORT ON;");
идеале это должно быть выполнено один раз, после открытия соединения с БД, а не для каждого запроса.
Создайте перехватчик с помощью:
Это позволит вам изменить SQL перед выполнением, в этом случае вы можете просто префикс его: SET ARITHABORT ON;
. Недостатком здесь является то , что он будет в каждом запросе, если вы не хранить локальную переменную для фиксации состояния или не было выполнено и тест для этого каждый раз (который на самом деле не так много дополнительной работы, но с использованием ExecuteSqlCommand
в наверное проще).
Любой из них позволит вам справиться с этим в одном месте без изменения какого-либо существующего кода.
В противном случае , вы можете создать метод-оболочку, который делает это, подобно:
public static SqlDataReader ExecuteReaderWithSetting(SqlCommand CommandToExec)
{
CommandToExec.CommandText = "SET ARITHABORT ON;\n" + CommandToExec.CommandText;
return CommandToExec.ExecuteReader();
}
а затем просто измените текущие _Reader = _Command.ExecuteReader();
ссылки на _Reader = ExecuteReaderWithSetting(_Command);
.
Это также позволяет обрабатывать настройки в одном месте, при этом требуются лишь минимальные и упрощенные изменения кода, которые в основном можно выполнить с помощью функции «Найти и заменить».
Еще лучше ( остальное часть 2), поскольку это настройка уровня соединения, ее не нужно выполнять для каждого вызова SqlCommand.Execute __ (). Таким образом, вместо создания оболочки для ExecuteReader()
, создайте оболочку для Connection.Open()
:
public static void OpenAndSetArithAbort(SqlConnection MyConnection)
{
using (SqlCommand _Command = MyConnection.CreateCommand())
{
_Command.CommandType = CommandType.Text;
_Command.CommandText = "SET ARITHABORT ON;";
MyConnection.Open();
_Command.ExecuteNonQuery();
}
return;
}
А затем просто замените существующие _Connection.Open();
ссылки на OpenAndSetArithAbort(_Connection);
.
Обе вышеприведенные идеи могут быть реализованы в большем количестве ОО-стилей путем создания класса, который расширяет либо SqlCommand, либо SqlConnection.
Или еще лучше ( остальное часть 3), вы можете создать обработчик событий для Connection StateChange и задать ему свойство при изменении соединения Closed
на Open
следующее:
protected static void OnStateChange(object sender, StateChangeEventArgs args)
{
if (args.OriginalState == ConnectionState.Closed
&& args.CurrentState == ConnectionState.Open)
{
using (SqlCommand _Command = ((SqlConnection)sender).CreateCommand())
{
_Command.CommandType = CommandType.Text;
_Command.CommandText = "SET ARITHABORT ON;";
_Command.ExecuteNonQuery();
}
}
}
Имея это в виду, вам нужно только добавить следующее в каждое место, где вы создаете SqlConnection
экземпляр:
_Connection.StateChange += new StateChangeEventHandler(OnStateChange);
Никаких изменений в существующий код не требуется. Я только что попробовал этот метод в небольшом консольном приложении, тестируя, печатая результат SELECT SESSIONPROPERTY('ARITHABORT');
. Он возвращается 1
, но если я отключаю обработчик событий, он возвращается 0
.
Для полноты картины вот некоторые вещи, которые не работают (либо вообще, либо не так эффективно):
- Триггеры входа в систему : триггеры, даже если они выполняются в том же сеансе и даже если они выполняются в явно запущенной транзакции, все еще являются подпроцессом, и, следовательно, его настройки (
SET
команды, локальные временные таблицы и т. Д.) Являются локальными для него и не сохраняются конец этого подпроцесса.
- Добавление
SET ARITHABORT ON;
в начало каждой хранимой процедуры:
- это требует большой работы для существующих проектов, особенно с увеличением числа хранимых процедур
- это не помогает специальным запросам
SELECT DATABASEPROPERTYEX('{database_name}', 'IsArithmeticAbortEnabled');
возврате 1 sys.dm_exec_sessions отключает arithabort, хотя я не вижу явных SET в Profiler. С чего бы это?Опция 1
Помимо решения Sankar , настройка арифметического прерывания на уровне сервера будет работать для всех соединений:
Начиная с SQL 2014 рекомендуется использовать все соединения:
Так что это, казалось бы, идеальное решение.
Вариант 2
Если вариант 1 нежизнеспособен и вы используете хранимые процедуры для большинства ваших вызовов SQL (что следует сделать, см. « Хранимые процедуры против встроенного SQL» ), просто включите параметр в каждой соответствующей хранимой процедуре:
Я считаю, что лучшее реальное решение здесь - просто отредактировать ваш код, так как это неправильно, а любое другое исправление - это просто обходной путь.
источник
set ArithAbort off
. Я надеялся на то, что можно было бы сделать на стороне .net / C #. Я выставил награду, потому что видел рекомендацию.Я не эксперт здесь, но вы можете попробовать что-то вроде ниже.
Ссылка: http://social.msdn.microsoft.com/Forums/en-US/transactsql/thread/d9e3e8ba-4948-4419-bb6b-dd5208bd7547/
источник
Нет настройки, чтобы заставить SqlClient всегда включать ARITHABORT, вы должны установить это так, как вы описываете.
Интересно, что из документации Microsoft для SET ARITHABORT : -
И все же .Net соединение жестко запрограммировано, чтобы отключить это по умолчанию?
Другой момент: вы должны быть очень осторожны при диагностике проблем производительности с этим параметром. Различные параметры набора приведут к различным планам запросов для одного и того же запроса. В вашем .Net-коде может возникнуть проблема с производительностью (SET ARITHABORT OFF), но при запуске того же запроса TSQL в SSMS (по умолчанию SET ARITHABORT ON) все может быть в порядке. Это связано с тем, что план запросов .Net не будет использоваться повторно и будет создан новый план. Это может, например, устранить проблему с анализом параметров и значительно повысить производительность.
источник
ANSI_WARNINGS
в более поздних версиях, и такие вещи, как индексированные представления, работают нормально.Если в моем случае это сэкономит кому-то время (Entity Framework Core 2.0.3, ASP.Net Core API, SQL Server 2008 R2):
user_options
были приемлемы для меня (они действительно работают - я проверял), но я не мог рисковать воздействием на другие приложения.Специальный запрос от EF Core (
SET ARITHABORT ON;
вверху) НЕ работает.Наконец, решение, которое работало для меня, заключалось в следующем: объединение хранимой процедуры, вызываемой как необработанный запрос, с
SET
опцией передEXEC
точкой с запятой, например:источник
Опираясь на ответ Соломона Руци , для EF6:
Это использует
System.Data.Common
«SDbCommand
вместоSqlCommand
, иDbConnection
вместоSqlConnection
.Трассировка SQL Profiler подтверждает,
SET ARITHABORT ON
отправляется при открытии соединения, прежде чем какие-либо другие команды будут выполнены в транзакции.источник