Desempenho do servidor vinculado do SQL Server: Por que as consultas remotas são tão caras?

14

Eu tenho dois servidores de banco de dados, conectados via servidores vinculados. Ambos são bancos de dados do SQL Server 2008R2 e a conexão do servidor vinculado é feita por um link "SQL Server" regular, usando o contexto de segurança do logon atual. Os servidores vinculados estão no mesmo centro de dados, portanto, a conexão não deve ser um problema.

Eu uso a seguinte consulta para verificar quais valores da coluna identifierestão disponíveis remotamente, mas não localmente.

SELECT 
    identifier 
FROM LinkedServer.RemoteDb.schema.[TableName]

EXCEPT

SELECT DISTINCT
    identifier 
FROM LocalDb.schema.[TableName] 

Nas duas tabelas há índices não agrupados na coluna identifier. Localmente, existem cerca de 2,6 milhões de linhas, remotamente, apenas 54. No entanto, ao analisar o plano de consulta, 70% do tempo de execução é dedicado à "execução de consulta remota". Além disso, ao estudar o plano de consulta completo, o número de linhas locais estimadas é em 1vez de 2695380(que é o número de linhas estimadas ao selecionar apenas a consulta seguinte EXCEPT). Plano de execução Ao executar esta consulta, leva muito tempo.

Isso me faz pensar: por que isso? A estimativa está "apenas" muito distante, ou as consultas remotas nos servidores vinculados são realmente tão caras?

vstrien
fonte
2
BTW: É o "número estimado de execuções" que você deve procurar pela pesquisa de índice. O número estimado de linhas é a saída de linhas por execução que não estará relacionada ao número de linhas na própria tabela, a menos que o plano tenha uma varredura completa.
Martin Smith

Respostas:

9

O plano que você tem no momento parece o melhor para mim.

Não concordo com a afirmação nas outras respostas de que ele está enviando as linhas de 2.6 milhões para o servidor remoto.

O plano parece-me que, para cada uma das 54 linhas retornadas da consulta remota, ele esteja executando uma pesquisa de índice em sua tabela local para determinar se é ou não compatível. Este é praticamente o plano ideal.

Substituir por uma junção de hash ou junção de mesclagem seria contraproducente, dado o tamanho da tabela e a adição de uma #temptabela intermediária apenas adiciona uma etapa adicional que parece não oferecer nenhuma vantagem.

Martin Smith
fonte
6

Conectar-se a um recurso remoto é caro. Período.

Uma das operações mais caras em qualquer ambiente de programação é a E / S de rede (embora a E / S de disco tenda a diminuí-la).

Isso se estende aos servidores vinculados remotos. O servidor que está chamando o servidor vinculado remoto precisa primeiro estabelecer uma conexão; depois, uma consulta precisa ser executada no servidor remoto, os resultados retornados e a conexão fechada. Tudo isso leva tempo na rede.


Você também deve estruturar sua consulta de forma a transferir os dados mínimos pela conexão. Não espere que o banco de dados otimize para você.

Se eu escrevesse essa consulta, selecionaria os dados remotos em uma variável de tabela (ou em uma tabela temporária) e usaria isso em conjunto com a tabela local. Isso garante que apenas os dados que precisam ser transferidos o sejam.

A consulta que você está executando pode facilmente enviar 2,6 milhões de linhas para o servidor remoto para processar a EXCEPTcláusula.

Oded
fonte
Ok, por isso tem altos custos de inicialização para configurar a conexão. A consulta precisa ser enviada, processada remotamente (nenhuma rede é necessária para essa) e, finalmente, os resultados enviados de volta e processados. Mas não vai demorar alguns minutos para enviar dados através de uma conexão de rede, não é?
vstrien
@ vstrien - Poderia. Depende da conexão de rede, latência, saturação e outros fatores. Aponte ser - não é determinístico.
@ vstrien - Adicionado mais informações na minha resposta. Acredito que a consulta conforme escrita enviará as linhas locais para o servidor remoto para processamento.
2
De onde você deduz o fato de que está enviando as linhas de 2,6 milhões para o servidor remoto? Não tenho muita experiência com planos com operadores de consulta remota, mas parece que as 54 linhas estão saindo do operador de consulta remota e, em seguida, está fazendo a junção anti-semi na tabela local.
Martin Smith
2
@ Lieven - Pode ser lógico, mas não acho que esteja correto a partir do plano mostrado.
Martin Smith
1

Não sou especialista, mas se você estiver usando Union, Except ou Intersect, não precisará usar "Distinct". Dependendo dos valores do LocalDb.schema. [TableName], o desempenho da consulta pode ser aprimorado.

SELECT 
    identifier 
FROM LinkedServer.RemoteDb.schema.[TableName]

EXCEPT

SELECT 
    identifier 
FROM LocalDb.schema.[TableName]
joakon
fonte
0

Oded está certo, o problema de desempenho é causado pelo envio das linhas de 2.6 milhões para o servidor remoto.

Para corrigir esse problema, você pode forçar o envio de dados remotos (54 linhas) usando uma tabela temporária ou na memória.

Usando uma tabela temporária

SELECT  identifier 
INTO    #TableName
FROM    LinkedServer.RemoteDb.schema.[TableName]

SELECT  identifier
FROM    #TableName
EXCEPT
SELECT  DISTINCT identifier 
FROM    LocalDb.schema.[TableName] 

DROP    #TableName
Lieven Keersmaekers
fonte
O uso de uma tabela temporária pode ajudar com estimativas de cardinalidade em qualquer caso, embora um loop aninhado pareça razoável por apenas 54 linhas.
Martin Smith
Usar uma tabela temporária funciona corretamente com 54 linhas; mas nos casos com tabelas grandes dos dois lados, não é mais possível. Qual seria a sua solução para duas tabelas "grandes" do mesmo tamanho? Criando uma tabela de usuário, em outro banco de dados?
vstrien
1
@ vstrien - não há realmente uma boa solução para duas mesas enormes do mesmo tamanho. Talvez a criação de uma Visualização Particionada Distribuída seja do seu interesse, mas não tenho nenhuma experiência com ela.
Lieven Keersmaekers
0

Eu acho que é melhor replicar a tabela remota para o servidor do qual você está consultando e depois executar todo o seu SQL localmente.

Alen
fonte