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
SELECT DATABASEPROPERTYEX('{database_name}', 'IsArithmeticAbortEnabled');
devolver 1, sys.dm_exec_sessions muestra arithabort apagado, aunque no veo ningún SET explícito en Profiler. ¿Por qué sería esto?Opción 1
Además de la solución de Sankar , funcionará la configuración de aborto aritmético en el nivel del servidor para todas las conexiones:
A partir de SQL 2014, se recomienda activar todas las conexiones:
Entonces, esta parece ser la solución ideal.
opcion 2
Si la opción 1 no es viable y utiliza procedimientos almacenados para la mayoría de sus llamadas SQL (lo cual debería hacer, consulte Procedimientos almacenados vs. SQL en línea ), entonces simplemente active la opción en cada procedimiento almacenado relevante:
Creo que la mejor solución real aquí es simplemente editar su código, ya que está mal y cualquier otra solución es simplemente una solución.
fuente
set ArithAbort off
. Esperaba algo que pudiera hacerse en el lado .net / C #. Puse la recompensa, porque había visto la recomendación.No soy un experto aquí, pero puedes probar algo como a continuación.
Ref: http://social.msdn.microsoft.com/Forums/en-US/transactsql/thread/d9e3e8ba-4948-4419-bb6b-dd5208bd7547/
fuente
No hay una configuración que obligue a SqlClient a activar ARITHABORT siempre, debe configurarlo como lo describe.
Curiosamente, de la documentación de Microsoft para SET ARITHABORT : -
¿Y sin embargo, la conexión .Net está codificada para configurar esto de forma predeterminada?
Como otro punto, debe tener mucho cuidado al diagnosticar problemas de rendimiento con esta configuración. Las diferentes opciones establecidas darán como resultado diferentes planes de consulta para la misma consulta. Su código .Net podría experimentar un problema de rendimiento (SET ARITHABORT OFF) y, sin embargo, cuando ejecuta la misma consulta TSQL en SSMS (SET ARITHABORT ON por defecto) podría estar bien. Esto se debe a que el plan de consulta .Net no se reutilizará y se generará un nuevo plan. Esto podría eliminar un problema de detección de parámetros, por ejemplo, y proporcionar un rendimiento mucho mejor.
fuente
ANSI_WARNINGS
en en versiones posteriores y cosas como las vistas indexadas funcionan bien.Si ahorra algo de tiempo a alguien, en mi caso (Entity Framework Core 2.0.3, ASP.Net Core API, SQL Server 2008 R2):
user_options
fue aceptable para mí (sí funcionan, lo probé), pero no podía arriesgarme a afectar otras aplicaciones.Una consulta ad-hoc de EF Core, con
SET ARITHABORT ON;
en la parte superior, NO funciona.Finalmente, la solución que funcionó para mí fue: Combinar un procedimiento almacenado, llamado como una consulta sin procesar con la
SET
opción antesEXEC
separada por un punto y coma, como este:fuente
Sobre la base de la respuesta de Solomon Rutzy , para EF6:
Esto usa
System.Data.Common
's enDbCommand
lugar deSqlCommand
y enDbConnection
lugar deSqlConnection
.Una traza de SQL Profiler confirma que
SET ARITHABORT ON
se envía cuando se abre la conexión, antes de que se ejecuten otros comandos en la transacción.fuente