Enfoque aparentemente preferido
Tenía la impresión de que los siguientes ya habían sido probados por otros, especialmente en base a algunos de los comentarios. Pero mis pruebas muestran que estos dos métodos realmente funcionan en el nivel de base de datos, incluso cuando se conectan a través de .NET SqlClient
. Estos han sido probados y verificados por otros.
En todo el servidor
Puede establecer la configuración de configuración del servidor de opciones de usuario para que sea lo que está OR
editado actualmente con 64 (el valor para ARITHABORT
). Si no utiliza el OR ( |
) a nivel de bits, sino que realiza una asignación directa ( =
), eliminará cualquier otra opción existente ya habilitada.
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
Nivel de base de datos
Esto se puede configurar por base de datos a través de 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;
Enfoques alternativos
La noticia no tan buena es que he buscado mucho sobre este tema, solo para descubrir que a lo largo de los años muchos otros han buscado mucho sobre este tema, y no hay forma de configurar el comportamiento de SqlClient
. Parte de la documentación de MSDN implica que se puede hacer a través de ConnectionString, pero no hay palabras clave que permitan modificar esta configuración. Otro documento implica que se puede cambiar a través de Client Network Configuration / Configuration Manager, pero eso tampoco parece posible. Por lo tanto, y desafortunadamente, deberá ejecutarlo SET ARITHABORT ON;
manualmente. Aquí hay algunas formas de considerar:
SI está utilizando Entity Framework 6 (o más reciente), puede intentar:
Use Database.ExecuteSqlCommand : context.Database.ExecuteSqlCommand("SET ARITHABORT ON;");
idealmente, esto se ejecutaría una vez, después de abrir la conexión de base de datos, y no por cada consulta.
Cree un interceptor a través de:
Esto le permitirá modificar el SQL antes de ser ejecutado, en cuyo caso puede simplemente como prefijo: SET ARITHABORT ON;
. La desventaja aquí es que será por cada consulta, a menos que almacene una variable local para capturar el estado de si se ha ejecutado o no y probar eso cada vez (lo que realmente no es mucho trabajo adicional, pero usar ExecuteSqlCommand
es probablemente más fácil).
Cualquiera de ellos le permitirá manejar esto en un solo lugar sin cambiar ningún código existente.
ELSE , podría crear un método de envoltura que haga esto, similar a:
public static SqlDataReader ExecuteReaderWithSetting(SqlCommand CommandToExec)
{
CommandToExec.CommandText = "SET ARITHABORT ON;\n" + CommandToExec.CommandText;
return CommandToExec.ExecuteReader();
}
y luego simplemente cambia las _Reader = _Command.ExecuteReader();
referencias actuales a be _Reader = ExecuteReaderWithSetting(_Command);
.
Hacer esto también permite que la configuración se maneje en una sola ubicación, mientras que solo requiere cambios de código mínimos y simplistas que se pueden hacer principalmente a través de Buscar y reemplazar.
Mejor aún ( otra parte 2), dado que esta es una configuración de nivel de conexión, no necesita ejecutarse por cada llamada SqlCommand.Execute __ (). Entonces, en lugar de crear un contenedor para ExecuteReader()
, cree un contenedor para 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;
}
Y luego simplemente reemplace las _Connection.Open();
referencias existentes para ser OpenAndSetArithAbort(_Connection);
.
Ambas ideas anteriores se pueden implementar en más estilo OO creando una Clase que amplíe SqlCommand o SqlConnection.
O mejor aún ( Else Parte 3), se puede crear un controlador de eventos para la conexión y la tengan StateChange Se establece la propiedad cuando los cambios de conexión de Closed
a Open
de la siguiente manera:
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();
}
}
}
Con eso en su lugar, solo necesita agregar lo siguiente a cada lugar donde cree una SqlConnection
instancia:
_Connection.StateChange += new StateChangeEventHandler(OnStateChange);
No se necesitan cambios en el código existente. Acabo de probar este método en una pequeña aplicación de consola, probando imprimiendo el resultado de SELECT SESSIONPROPERTY('ARITHABORT');
. Regresa 1
, pero si desactivo el controlador de eventos, regresa 0
.
En aras de la exhaustividad, aquí hay algunas cosas que no funcionan (en absoluto o no de manera tan efectiva):
- Activadores de inicio de sesión : los activadores, incluso mientras se ejecutan en la misma sesión, e incluso si se ejecutan dentro de una transacción iniciada explícitamente, siguen siendo un subproceso y, por lo tanto, su configuración (
SET
comandos, tablas temporales locales, etc.) son locales y no sobreviven El final de ese subproceso.
- Agregando
SET ARITHABORT ON;
al comienzo de cada procedimiento almacenado:
- Esto requiere mucho trabajo para los proyectos existentes, especialmente a medida que aumenta el número de procedimientos almacenados
- esto no ayuda a las consultas ad hoc