Problemas de desempenho do SQL com consulta remota no servidor vinculado

8

Este sproc

create proc dbo.Get_Accounts as
begin
  declare @current_date datetime
  set @current_date = dbo.fn_currdate()

  select [fields]
  into dbo.current_accounts
  from linkedserver.database.dbo.accounts
  where date = @current_date
end

falha continuamente após 10 minutos com a seguinte mensagem de erro:

Servidor: Msg 7399, nível 16, estado 1, linha 1 provedor OLE DB 'SQLOLEDB' relatou um erro. Execução finalizada pelo provedor porque um limite de recurso foi atingido. [Provedor OLE / DB retornou mensagem: Tempo limite expirado] Rastreamento de erro do OLE DB [Provedor OLE / DB 'SQLOLEDB' ICommandText :: Execute retornou 0x80040e31: Execução finalizada pelo provedor porque um limite de recurso foi atingido.].

No entanto, quando executo a mesma consulta no mesmo banco de dados (não no remoto) em uma janela de consulta interativa com a data codificada:

  select [fields]
  into dbo.current_accounts
  from linkedserver.database.dbo.accounts
  where date = '1/20/2012'

Retorna em 30 segundos.

O servidor local é o SQLSERVER 2008, o remoto é o SQLSERVER 2000.

Fizemos o seguinte sem sucesso:

  • Recriou o processo armazenado.
  • sp_recompile no processo armazenado
  • atualizar estatísticas em dbo.accounts
  • caiu e recriou os índices em dbo.accounts
  • caiu o índice em dbo.accounts e tente
  • DBCC FREEPROCCACHE & DBCC DROPCLEANBUFFERS nos servidores local e remoto
  • Reiniciou o servidor remoto (não é uma opção fácil no local)

Questões

  • Alguém pode explicar esse comportamento bizarro?
  • Alguma sugestão sobre outras opções para corrigi-lo?
Bob Probst
fonte

Respostas:

11

Você pode ativar o sinalizador de rastreamento 7300, que pode fornecer uma mensagem de erro mais detalhada

Quantas linhas uma consulta representativa retorna? Quão rápida / confiável é a conexão de rede entre os dois servidores?

É possível que um grande conjunto de dados esteja demorando muito para ser transferido (além do tempo real da consulta). Você pode aumentar o valor do tempo limite.

Você pode tentar reconfigurar a configuração de tempo limite da seguinte maneira:

Defina o tempo limite do login remoto para 300 segundos:

sp_configure 'remote login timeout', 300
go 
reconfigure with override 
go 

Defina o tempo limite da consulta remota como 0 (espera infinita):

sp_configure 'remote query timeout', 0 
go 
reconfigure with override 
go 

Atualização : SQL Server 2012 SP1 em diante : os usuários com SELECTpermissão poderão acessar, o DBCC SHOW_STATISTICSque melhorará o desempenho somente leitura em servidores vinculados. Ref: https://msdn.microsoft.com/en-us/library/ms174384(v=sql.110).aspx

Atualização : você está certo ao dizer que não é o tamanho dos dados ou a velocidade da conexão. Tocou uma campainha na minha memória nebulosa e lembrei-me de onde a tinha visto: Lento no aplicativo, Rápido no SSMS? (Um problema com servidores vinculados). Não é o sniffing de parâmetros, são as próprias estatísticas que estão ausentes (devido a permissões), fazendo com que um plano de consulta incorreto seja usado:

Você pode ver que as estimativas são diferentes. Quando eu executei como administrador de sistemas, a estimativa era de 1 linha, que é um número correto, pois não há Pedidos no Northwind em que o ID do pedido excede 20000. Mas quando eu executei como usuário comum, a estimativa era de 249 linhas. Reconhecemos esse número específico como 30% de 830 pedidos ou a estimativa para uma operação de desigualdade quando o otimizador não possui informações. Anteriormente, isso era devido a um valor de variável desconhecido, mas nesse caso não há variável que possa ser desconhecida. Não, são as próprias estatísticas que estão faltando.

Desde que uma consulta acesse apenas tabelas no servidor local, o otimizador sempre pode acessar as estatísticas de todas as tabelas na consulta; não há verificações de permissão extras. Mas isso é diferente com as tabelas em um servidor vinculado. Quando o SQL Server acessa um servidor vinculado, não há protocolo secreto usado apenas para comunicação entre servidores. Não, o SQL Server usa a interface OLE DB padrão para servidores vinculados, seja outras instâncias do SQL Server, Oracle, arquivos de texto ou sua fonte de dados fabricada em casa e se conecta como qualquer outro usuário. Exatamente como as estatísticas são recuperadas depende da fonte de dados e do provedor OLE DB em questão. Nesse caso, o provedor é o SQL Server Native Client, que recupera as estatísticas em duas etapas. (Você pode ver isso executando o Profiler no servidor remoto). Primeiro, o provedor executa o procedimento sp_table_statistics2_rowset, que retorna informações sobre quais estatísticas de coluna existem, bem como suas informações de cardinalidade e densidade. Na segunda etapa, o provedor executa o DBCC SHOW_STATISTICS, um comando que retorna as estatísticas completas da distribuição. (Examinaremos este comando mais adiante neste artigo.) Aqui está o problema: para executar o DBCC SHOW_STATISTICS, você deve ser membro da função de servidor sysadmin ou de qualquer uma das funções de banco de dados db_owner ou db_ddladmin.

E é por isso que obtive resultados diferentes. Ao executar como sysadmin, obtive as estatísticas de distribuição completas que indicavam que não há linhas com ID do pedido> 20000, e a estimativa era de uma linha. (Lembre-se de que o otimizador nunca assume zero linhas das estatísticas.) Mas, ao executar como usuário comum, o DBCC SHOW_STATISTICS falhou com um erro de permissão. Este erro não foi propagado, mas o otimizador aceitou que não havia estatísticas e usou suposições padrão. Como ele obteve informações de cardinalidade, soube que a tabela remota tem 830 linhas, daí a estimativa de 249 linhas.

Sempre que encontrar um problema de desempenho em que uma consulta que inclua acesso a um servidor vinculado seja lenta no aplicativo, mas seja executada com rapidez ao testá-lo no SSMS, você deve sempre investigar se permissões insuficientes no banco de dados remoto podem ser a causa. (Lembre-se de que o acesso ao servidor vinculado pode não estar aberto na consulta, mas pode estar oculto em uma exibição.) Se você determinar que as permissões no banco de dados remoto são o problema, que ações você poderá executar?

  • Você pode adicionar os usuários à função db_ddladmin, mas como isso lhes dá o direito de adicionar e excluir tabelas, isso não é recomendável.

  • Por padrão, quando os usuários se conectam a um servidor remoto, eles se conectam como eles mesmos, mas você pode configurar um mapeamento de logon com sp_addlinkedsrvlogin, para que os usuários mapeiem para uma conta proxy que seja db_ddladmin. Observe que esta conta proxy deve ser um logon SQL, portanto, essa não é uma opção se o servidor remoto não tiver a autenticação SQL ativada. Essa solução também é um tanto duvidosa do ponto de vista da segurança, embora seja melhor a sugestão anterior.

  • Em alguns casos, você pode reescrever a consulta com OPENQUERY para forçar a avaliação no servidor remoto. Isso pode ser particularmente útil se a consulta incluir várias tabelas remotas. (Mas também pode sair pela culatra, porque o otimizador agora obtém ainda menos informações estatísticas do servidor remoto.)

  • Obviamente, você pode usar toda a bateria de dicas e guias de plano para obter o plano que deseja.

  • Por fim, você deve se perguntar se esse acesso ao servidor vinculado é necessário. Talvez os bancos de dados possam estar no mesmo servidor? Os dados podem ser replicados? Alguma outra solução?

Mitch Wheat
fonte
Ele retorna cerca de 140 mil registros. mas como ele funciona bem quando o valor da data é codificado permanentemente, não consigo pensar em um problema de E / S ou de rede que afetaria a versão parametrizada de maneira tão extrema. Meu instinto diz que a consulta está sendo passada para o servidor remoto e o otimizador remoto de alguma forma escolhe um plano de consulta incorreto quando não consegue entender o parâmetro. Mas reindexar e limpar o cache / buffers deve corrigir isso (presumo). Examinarei os intervalos para ver se conseguimos fazê-lo pelo menos retornar. Obrigado
11
Excelente resposta e explicou exatamente o problema que estava tendo, obrigado. Eu acrescentaria que, de acordo com o MSDN , do SQL2012 SP1 em diante, os usuários com SELECTpermissão poderão acessar, o DBCC SHOW_STATISTICSque melhorará o desempenho somente leitura em servidores vinculados sem comprometer a segurança.
Steve Pettifer
2

O que acontece quando você tenta fazer isso (ou seja, indica explicitamente o que deve ser executado no servidor remoto) ?:

select [fields]
into dbo.current_accounts
from OPENQUERY(linkedserver, 'SELECT [fields] FROM database.dbo.accounts where date = ''1/20/2012''');

Suspeito que, no seu caso acima do SQL Server, esteja apenas puxando a tabela inteira do servidor remoto e executando a consulta localmente (já vi isso acontecer várias vezes no passado). Prefiro ser explícito (usando o OPENQUERY ou criando um SP no servidor remoto) para que não haja chance de confusão.

Gareth
fonte
1

Como esse é um problema de recursos, o pool de memória fora do servidor SQL usado para carregar drivers externos e o CLR pode estar próximo do seu limite. O padrão é 256MB. Para contornar isso, sugiro que você vá para o gerenciador de configuração do SQL Server, guia avançado e adicione a opção -g ao final dos parâmetros de inicialização.ie; -g1024 e reinicie o serviço do SQL Server. Eu costumo fazer isso porque usamos um número alto de servidores vinculados. http://msdn.microsoft.com/en-us/library/ms190737.aspx

Nopol
fonte
1

Eu tenho duas idéias que podem ajudar. Também vou dizer a você que tive má sorte com desempenho executando consultas em servidores vinculados. Portanto, minha primeira recomendação é evitá-lo, se puder.

Minha primeira idéia é instalar o procedimento armazenado na caixa SQL Server 2000, referenciando o servidor local. Você pode executar o procedimento armazenado remotamente.

exec linkedserver.database.dbo.Get_Accounts

Se você pode seguir esse caminho, deve melhorar tremendamente o desempenho.

Minha segunda idéia é obter o plano de consulta estimado ao executar o procedimento armazenado. Está mostrando a você o que está demorando tanto? Um problema em potencial é que a conta que você está usando no servidor vinculado pode não ter autoridade suficiente para acessar as estatísticas da tabela (você precisa de mais autoridade para o servidor vinculado do que para o servidor local). E isso pode tornar as consultas incrivelmente lentas. Você pode ler mais sobre esse problema específico aqui .

Jeff Siver
fonte