Abordagem aparentemente preferida
Fiquei com a impressão de que o seguinte já havia sido testado por outras pessoas, especialmente com base em alguns dos comentários. Mas meus testes mostram que esses dois métodos realmente funcionam no nível do banco de dados, mesmo ao conectar via .NET SqlClient
. Estes foram testados e verificados por outros.
Em todo o servidor
É possível definir a configuração do servidor de opções do usuário para o que for atualmente definido em bits OR
com 64 (o valor para ARITHABORT
). Se você não usar o OR (em bits |
), mas fizer uma atribuição direta ( =
), eliminará todas as outras opções existentes já ativadas.
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
No nível do banco de dados
Isso pode ser definido por banco de dados via 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;
Abordagens alternativas
A notícia não tão boa é que eu pesquisei bastante esse tópico, apenas para descobrir que, ao longo dos anos, muitos outros pesquisaram muito sobre esse assunto, e não há como configurar o comportamento de SqlClient
. Algumas documentações do MSDN indicam que isso pode ser feito por meio de um ConnectionString, mas não há palavras-chave que permitam alterar essas configurações. Outro documento implica que ele pode ser alterado via Gerenciador de Configuração / Configuração de Rede do Cliente, mas isso também não parece possível. Portanto, e, infelizmente, você precisará executar SET ARITHABORT ON;
manualmente. Aqui estão algumas maneiras de considerar:
Se você estiver usando o Entity Framework 6 (ou mais recente), você pode tentar:
Use Database.ExecuteSqlCommand : context.Database.ExecuteSqlCommand("SET ARITHABORT ON;");
Idealmente, isso seria executado uma vez, após abrir a conexão com o banco de dados, e não por cada consulta.
Crie um interceptor via:
Isso permitirá que você modifique o SQL antes de ser executado, caso em que você pode simplesmente prefixo com: SET ARITHABORT ON;
. A desvantagem aqui é que será por cada consulta, a menos que você armazene uma variável local para capturar o estado de se ela foi executada ou não e teste para cada vez (o que realmente não é muito trabalho extra, mas usar ExecuteSqlCommand
é provavelmente mais fácil).
Qualquer um deles permitirá que você lide com isso em um único local sem alterar nenhum código existente.
ELSE , você pode criar um método de wrapper que faça isso, semelhante a:
public static SqlDataReader ExecuteReaderWithSetting(SqlCommand CommandToExec)
{
CommandToExec.CommandText = "SET ARITHABORT ON;\n" + CommandToExec.CommandText;
return CommandToExec.ExecuteReader();
}
e depois basta alterar as _Reader = _Command.ExecuteReader();
referências atuais _Reader = ExecuteReaderWithSetting(_Command);
.
Isso também permite que a configuração seja manipulada em um único local, exigindo apenas alterações de código mínimas e simplistas que podem ser feitas principalmente via Localizar e substituir.
Melhor ainda ( outra parte 2), como essa é uma configuração de nível de conexão, ela não precisa ser executada a cada chamada SqlCommand.Execute __ (). Portanto, em vez de criar um wrapper para ExecuteReader()
, crie um wrapper 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;
}
E então apenas substitua as _Connection.Open();
referências existentes OpenAndSetArithAbort(_Connection);
.
Ambas as idéias acima podem ser implementadas em mais estilos OO, criando uma classe que estenda SqlCommand ou SqlConnection.
Ou melhor ainda ( outra parte 3), você pode criar um manipulador de eventos para o Connection StateChange e definir a propriedade quando a conexão mudar de Closed
para da Open
seguinte maneira:
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();
}
}
}
Com isso em vigor, você só precisará adicionar o seguinte a cada local em que criar uma SqlConnection
instância:
_Connection.StateChange += new StateChangeEventHandler(OnStateChange);
Nenhuma alteração no código existente é necessária. Eu apenas tentei esse método em um aplicativo de console pequeno, testando imprimindo o resultado de SELECT SESSIONPROPERTY('ARITHABORT');
. Ele retorna 1
, mas se eu desativar o Manipulador de Eventos, ele retornará 0
.
Por uma questão de completude, eis algumas coisas que não funcionam (ou não são tão eficazes):
- Disparadores de logon : Os disparadores, mesmo durante a execução na mesma sessão, e mesmo sendo executados em uma transação explicitamente iniciada, ainda são um subprocesso e, portanto, suas configurações (
SET
comandos, tabelas temporárias locais, etc.) são locais e não sobrevivem. o fim desse subprocesso.
- Adicionando
SET ARITHABORT ON;
ao início de cada procedimento armazenado:
- isso requer muito trabalho para projetos existentes, principalmente porque o número de procedimentos armazenados aumenta
- isso não ajuda a consultas ad hoc
SELECT DATABASEPROPERTYEX('{database_name}', 'IsArithmeticAbortEnabled');
retorno 1, sys.dm_exec_sessions mostra um elemento desativado, embora eu não veja nenhum SET explícito no Profiler. Por que isso seria?Opção 1
Além da solução da Sankar , a configuração da interrupção aritmética no nível do servidor para todas as conexões funcionará:
No SQL 2014, é recomendável estar ativado para todas as conexões:
Portanto, essa parece ser a solução ideal.
opção 2
Se a opção 1 não for viável e você usar procedimentos armazenados para a maioria das chamadas SQL (o que você deve, consulte Procedimentos armazenados versus SQL embutido ), basta ativar a opção em cada procedimento armazenado relevante:
Acredito que a melhor solução real aqui é simplesmente editar seu código, pois está errado e qualquer outra correção é apenas uma solução alternativa.
fonte
set ArithAbort off
. Eu esperava algo que pudesse ser feito no lado .net / C #. Eu ofereci a recompensa, porque eu tinha visto a recomendação.Eu não sou um especialista aqui, mas você pode tentar algo como abaixo.
Ref: http://social.msdn.microsoft.com/Forums/en-US/transactsql/thread/d9e3e8ba-4948-4419-bb6b-dd5208bd7547/
fonte
Não há nenhuma configuração para forçar o SqlClient a sempre ativar o ARITHABORT, você deve defini-lo conforme a descrição.
Curiosamente da documentação da Microsoft para SET ARITHABORT : -
E, no entanto, a conexão .Net é codificada para desativá-la por padrão?
Como outro ponto, você deve ter muito cuidado ao diagnosticar problemas de desempenho com essa configuração. Diferentes opções de conjunto resultarão em diferentes planos de consulta para a mesma consulta. Seu código .Net pode ter um problema de desempenho (SET ARITHABORT OFF) e, no entanto, quando você executa a mesma consulta TSQL no SSMS (SET ARITHABORT ON por padrão), pode estar tudo bem. Isso ocorre porque o plano de consulta .Net não será reutilizado e um novo plano será gerado. Isso poderia potencialmente eliminar um problema de detecção de parâmetros, por exemplo, e fornecer um desempenho muito melhor.
fonte
ANSI_WARNINGS
em versões posteriores e coisas como visualizações indexadas funcionam bem.Se isso poupar a alguém algum tempo, no meu caso (Entity Framework Core 2.0.3, API do ASP.Net Core, SQL Server 2008 R2):
user_options
foi aceitável alterar a configuração global do banco de dados nem a configuração (eles funcionam - eu testei), mas não corria o risco de impactar outros aplicativos.Uma consulta ad-hoc do EF Core, com
SET ARITHABORT ON;
na parte superior, NÃO funciona.Finalmente, a solução que funcionou para mim foi: Combinar um procedimento armazenado, chamado como uma consulta bruta, com a
SET
opção antesEXEC
separada por um ponto e vírgula, assim:fonte
Com base na resposta de Solomon Rutzy , para EF6:
Isso usa
System.Data.Common
's emDbCommand
vez deSqlCommand
e emDbConnection
vez deSqlConnection
.Um rastreamento do SQL Profiler confirma,
SET ARITHABORT ON
é enviado quando a conexão é aberta, antes que outros comandos sejam executados na transação.fonte