THE SQL TIMES

Respondendo os porquês sobre SQL Server, Windows, programação e outros assuntos sobre tecnologia

Kernel Mode vs User Mode

Aprofundar o conhecimento em um software, requer entender muitas características do sistema operacional. No caso de SO’s como o Windows, é comum, em cursos avançados ouvir as expressões “Kernel Mode” e “User Mode”. Com o intuito de fazer um rápido esclarecimento sobre o que significam estes nomes, eu preparei este post.

Certas áreas de memória contém dados vitais para o correto funcionamento do Windows. Por exemplo, imagine que no endereço  0xFFFF0000, o Windows guardasse a quantidade total de memória livre para alocação. Ora, se uma thread qualquer  altera esse valor, o Windows poderia achar que havia mais ou menos memória disponível para alocação. Isso traria instabilidade e incosistência para todo o sistema operacional, e, consequentemente, todos os processos em execução.

Para se prevenir deste tipo de caso, e outros, o Windows fornece privilégios que permitem ou impedem que uma thread acesse um determinado recurso, como certos endereços de memória. Na verdade, isso é possível graças ao processador: Nos primeiros momentos do boot, ele está livre e sem restrições, então o sistema operacional interage com ele e registra uma série de rotinas e códigos necessários para serem executados quando certos eventos ocorrem durante as execuções das instruções. Alguns destes eventos são disparados justamente quando uma thread necessita acessar algum recurso protegido. Diante disso, o processador irá executar o código que o sistema operacional registrou e o mesmo irá tratar de forma adequada o acesso. No exemplo acima, ao acessar o endereço de memória crítico, o Windows irá impedir a ação de ser executada e gerar um erro para a thread que tentou fazer o acesso.

Mas não é todo momento que uma thread deve ser impedida de acessar recursos críticos. Por exemplo, ao realizar um leitura de arquivo, a thread necessita chamar a função “ReadFile”, da API do Windows. Essa função vai executar um código que requer o acesso a estruturas protegidas pelo sistema operacional. Neste caso, se houver o impedimento por parte do sistema operacinal, a thread não irá conseguir efetuar a leitura do arquivo.

Para resolver isso, o Windows define dois modos de operação das threads:

  • User Mode
    O User Mode é o modo de operação em que as threads executam na maior parte do tempo. Neste modo, a thread não pode acessar recursos vitais para o funcionamento do sistema, como certos endereços de memória e registradores. Para acessar, é necessário entrar no “Kernel Mode”.
  • Kernel Mode
    Este é o modo sob o qual as threads que executam o código do sistema operam, já que o mesmo referencia estruturas internas para completar os serviços oferecidos. A API do Windows contém funções que executam instruções que fazem com que o sistema entre neste modo. Um leitor curioso, pode então, concluir que seria fácil burlar as proteções do Kernel Mode, bastando apenas executar esta instruções que ativam o Kernel Mode. Bom, não é bem assim.

Transição User Mode – Kernel Mode

Quando a thread executa a instrução que faz o modo de operação mudar para Kernel Mode, o processador interrompe a execução da mesma e passa o controle para umas dessas rotinas que o Windows registrou lá no boot. Isso significa, que graças ao suporte que o processador oferece, a thread passa a rodar um código confiável pelo Windows, isto é, que faz parte do kernel. Dessa maneira, ela deixa de executar o seu código original, e passa a executar um código específico para tratar este evento gerado pelo processador. O nome da instrução que solicita essa transição depende da arquitetura e família do processador. No caso de processadores Intel x64, o nome da instrução é syscall (Fonte: Intel® 64 and IA-32 Architectures, Página 1788). Esse processo tambem é conhecido como “uso dos serviços do sistema operacional”, pois é assim que um processo consegue interagir com as centenas de rotinas (os chamados “serviços”) que provê alguma funcionalidade do Windows (como ler arquivos, criar processos, transferir dados via rede, etc.).

Mesmo que o usuário utilizasse a instrução syscall em seu código diretamente, o código do sistema tomaria o controle da execução e impediria o usuário de realizar qualquer modificação que não fosse por parte de um código criado pelos desenvolvedores do Windows.

É comum observar nas literaturas a respeito da arquitetura do Windows, o fato de que a API do Windows possui uma parte User Mode e uma parte Kernel Mode. Utilizar a instrução syscall diretamente seria chato e complexo para os desenvolvedores. Ao realizar a transição para Kernel Mode, é necessário informar uma série de parâmetros (via registradores da CPU), que o código do Windows irá validar para determinar o que deverá ser feito a partir dali. Ao invés do desenvolvedor ter que decorar as centenas de códigos que são definidos, o Windows disponibiliza uma série de funções em DLLs como “kernel32.dll” e “user32.dll”. Essa funções são responsáveis por preparar os parâmetros e executar a instrução “syscall”.  Então, por isso, até que a instrução “syscall” seja executada, o código da DLL que faz parte do Windows, ainda estava rodando em User Mode, isto é, se houvesse uma tentativa de acessar um recurso protegido nesse momento, haveria uma falha (o que seria um bug no sistema operacional, já que a DLL faz parte do Windows). Por exemplo, a função ReadFile é definida na DLL “Kernel32.dll” (Fonte: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=vs.85%29.aspx). Essa é a função que deve ser usada sempre que um processo necessita ler um arquivo (ou uma de suas variações, como ReadFileEx). O SQL Server faz uso dessa função para ler o conteúdo dos arquivos de dados e log. Ao iniciar a sua execução, a função irá realizar todas as validações necessárias e irá executar outras funções que estão defindias em outras DLLs do Windows. E são essas funções que irão preparar e executar a instrução syscall.

Transição Kernel Mode – User Mode

Depois que o código do sistema operacional termina seu trabalho, é necessário retomar a execução do código original, isto é, o codigo que causou a transição para Kernel Mode. Mas antes, é necessário voltar ao User Mode, caso contrário, toda o esquema de proteção feito até aqui seria inútil.  Assim como existem instruções para entrar em Kernel Mode, existem para sair. De novo, o nome vai depender da família e arquitetura do processador. No caso de x64 , a instrução é a sysret ( Fonte: Intel® 64 and IA-32 Architectures, Página 1796  ). Quando o código do sistema operacional termina de fazer o que lhe foi solicitado, então ele executa a instrução sysret, saindo do Kernel Mode e retomando a execução do código após o syscall que causou a transição para Kernel Mode.

Mais alguns comentários…

 

Antes de encerrar, é importante fortalecer alguns pontos.

  1. Tudo isso foi um resumo do resumo da resenha do rascunho do que é realmente o Kernel Mode e o User Mode, e como ocorre toda essas transições. Se você quer se aprofundar no assunto, pode usar a referência que deixei no final do artigo (e, se ainda não o fez, aproveita para estudar C++ e Assembly, pois vai facilitar o entendimento de muita coisa).
  2. User Mode e Kernel Mode não são threads ou processos diferentes. Uma thread pode em um determinado momento estar em User Mode, e um outro determinado momento em Kernel Mode. O que muda é que em Kernel Mode ela estara executando um código do sistema operacional ou driver. Isso indica que se a thread passa muito tempo em Kernel Mode, é uma grande chance de ser um problema de hardware, uso intenso de recursos do SO ou bug do sistema (este último com chances bem menores, mas não impossível).

    Vida da thread e modos de operação

  3. Algumas ferramentas, como o gerenciador de tarefas e o Process Explorer, permite que você monitore o uso de CPU em Kernel Mode. Por exemplo, você consegue determinar quanto de tempo foi gasto pelas threads executando em Kernel Mode.

    O gráfico em vermelho mostra o tempo gasto pela CPU executando instruções sob o modo Kernel Mode. Também, é possivel obter informações por processo. Na imagem, é possível observar o texto “Kernel Time” na janela da direita. Esta informação indica o tempo total gasto em Kernel Mode pelo processo. O mesmo vale pro “User Time”.

  4. O que tudo isso tem a ver com SQL Server? Não somente com SQL Server, mas com qualquer software que rode no Windows. Todos eles fazem uso constante de serviços do sistema. Assim, entender o que é o Kernel Mode é útil para determinar se um possível problema está no sistema operacional ou no software. A transição para Kernel Mode é algo muito custoso do ponto de vista de um processo. Envolve a execução de mais algumas centenas instruções, acesso a memória, recursos compartilhados, etc. O SQL Server foi desenvolvido para evitar ao máximo fazer transições de User Mode para Kernel Mode, para salvar a perfomance. É obvio que existem casos onde não é possivel evitar isso, como no momento em que é necessário ler ou escrever dos arquivos. Mas é sempre bom estar de olho nas métricas relativo ao uso dos recursos em Kernel Mode.

 

Referências:

 

After SQLServerDF XXXIII: SQL Server CPU Foundations

Na última quarta-feira (29/06/2016) tive a oportunidade de apresentar o tema que gosto bastante: CPU. A apresentação “SQL Server: CPU Foundations” foi bem legal e apesar de ter falhado em umas das demos, gostei bastante.

Os scripts podem ser baixados no link https://drive.google.com/open?id=0B9MFBfb3HCHXNG9TM2pwcW1ILTg

A demo que falhou

Há uma demo nesta apresentação cujo o objetivo é demonstrar como é possível ter valores de CPU acima de 100%. Nesta demo, o SQL Server é configurado para rodar somente nas CPUs 2 e 3, além de abrir duas sessões que executam uma query que causa o uso de 100% de CPU.  O que se espera é ver o processo do SQL Server consumindo duas CPUs em 100%, uma em cada sessão, e causando os 200% de CPU no perfmon.

Porém, ao realizar esta demonstração, o SQL Server jogava as sessões apenas em uma CPU. Após analisar esse comportamento com mais calma, eu notei um detalhe que havia esquecido de considerar ao realizá-la: Os schedulers. Os schedulers são uma espécie de porta para a CPU. O SQL Server usa os schedulers para gerenciar a  execução de suas tarefas (workers, pra ser mais exato).  Toda tarefa tem um scheduler associado.  Baseado em alguns fatores, dentre eles, a carga do schedulers (quantas tarefas já estão “alocadas” no scheduler), o SQL Server escolhe em qual scheduler a task vai rodar.  Se duas tasks estão configuradas para rodar no mesmo scheduler, então, essas tasks podem acabar na mesma CPU.

E era isso o que ocorreu na demonstração. Os scripts acima contém os detalhes de como reproduzir a demo que falhou e contornar quando o SQL Server tentar alocar as duas conexões no mesmo scheduler.

 

Obrigado!

 

[]’s
Rodrigo Ribeiro Gomes

After SQL Server CPU Foundations – DevSQL #SQLSat512

Olá!

No dia 12/05/2016 fiz uma apresentação para o chapter DevSQL, como parte de uma prévia para o evento SQL Saturday #512, que irá acontecer dia 18/06/2016, no Rio de Janeiro!

Os arquivos da apresentação estão disponíveis neste link e incluem:

  • Os scripts usados nas demonstrações
  • O PDF da apresentação, contendo diversas notas semelhantes ao que foi falado
  • O PPS para reproduzir a apresentação, permitindo reproduzir as animações

Gravação: Houve um problema com a gravação, mas a última informação que tenho é que foi gravado da metade para a frente. Quando houver novas informações eu atualizo o post.

Mais uma vez agradeço a todos que reservaram um tempo do seu dia para assistir a apresentação. Se você tiver dúvidas, pode postar nos comentários.

Ah, se você quiser, pode avaliar a apresentação deixando seu feedback aqui neste formulário. Sua opinião sempre será bem vinda!

Copiando bases SQL Server com Copy-SQLDatabase

Copiar bases entre instâncias é procedimento muito comum em qualquer ambiente SQL, na maioria dos casos para manter ambientes de homologação, teste, desenvolvimento, etc. Esta tarefa pode ser muito simples, quando a base é pequena e tem poucos arquivos, ou complicada, quando a base é grande e há muitos arquivos envolvidos. A complexidade pode aumentar mais quando é preciso manter as permissões, executar scripts de expurgo, etc.  Pensando nisso, desenvolvi um script em powershell que tenta facilitar ao máximo este processo ao mesmo tempo que fornece uma série de recursos para este procedimento. Este artigo vai apresentar algum destes recursos!

Há um série de “pequenos probleminhas” que me incomodam bastante ao realizar restores de bancos de dados no SQL Server. Destaco os seguintes que contribuem para que este processo fique chato e cansativo:

  1. Estrutura de discos diferentes na instância de origem e destino
    Mount points, letras diferentes, espaço disponível, etc., são elementos que resultam em retrabalhos e podem acarretar erros no processo de RESTORE.
  2. Manter as permissões na base de destino
    Ao longo do tempo, diferentes usuários ganham diferentes tipos de acesso à base, e manter este controle para um posterior restore pode deixar mais caro ainda.
    Este é um tipo de solicitação bastante comum: Sobrescreva a base, mantendo os usuários e permissões!
  3. Executar scripts após a cópia
    É comum que um ou mais scripts precisem ser executados após o restore para, por exemplo, alterar a senha de todos os usuários para 123456. Estes scripts podem variar conforme a necessidade do responsável pela mesma.

Copy-SQLDatabase cuida de todos estas questões e muito mais, permitindo uma maneira mais flexível de copiar bases.

Pré-Requisitos

Para executar os exemplos a seguir você irá precisar do seguinte:

  • Powershell 2.0 ou superior (Instalado junto com o Windows a partir da versão 7/2008)
  • Módulo CustomMSSQL
    CustomMSSQL é um modulo em powershell, contendo vários cmdlets, inclusive Copy-SQLDatabase.
    O link para download está acima e a instalação é fácil e rápida.
    Para executar os comandos, é preciso importar o módulo usando o comando Import-Module. No link do download existem instruções de instalação e uso do módulo.
  • Pelo menos uma instância SQL Server 2005 ou superior (Óbvio que você não irá usar a produção para testes, ok?)
  • Ambiente powershell
    • Permita a execução de scripts: Abra o powershell como Administrador e execute o comando:
    • Certifique-se que sua máquina tenha acesso ao servidor de destino (computador onde a instância de destino está)
      • Verifique se o seguinte comando executa normalmente: Get-WmiObject Win32_Volume –ComputerName <IP-ou-Nome-Destino> | select Name
        • Em caso de falhas, verifique as permissões de acesso do WMI na máquina de destino.

 

Exemplo 1: Cópia simples

Neste exemplo, estamos usando a forma mais básica de cópia, através do método Backup/Restore via T-SQL. Apenas especificamos as informações de conexão como instância de origem e de destino, além do nome da base na origem e o nome que a base irá ter no destino. Por padrão, Windows Authentication será usado. O Copy-SQLDatabase ainda não permite a conexão usando SQL Authentication, mas deverá ser implementando na próxima versão. O diretório especificado no parâmetro “BackupFolder” indica o local onde o Backup será gerado. As contas de serviço das instâncias envolvidas deverão ter as devidas permissões neste diretório. Na origem, Copy-SQLDatabase irá tentar usar as opções COMPRESSION e COPY_ONLY, se suportados.

Note que não foi necessário especificar nenhum local para os arquivos. Este é uma das grandes facilidades fornecidas por Copy-SQLDatabase. O cmdlet irá tentar determinar o melhor local para os arquivos da base. Usando o backup de origem, ele irá determinar os arquivos existentes, bem como o tamanho, e irá gerar o comando de RESTORE adequadamente. Há alguns algoritmos que Copy-SQLDatabase irá usar para distribuir os arquivos nos volumes existentes no destino. O algoritmo usado vai depender de alguns fatores, como o conjunto de parâmetros informados. O comportamento padrão é o seguinte:

  • Se a base de destino não existe, então ele irá partir do maior arquivo e encontrar o volume com maior espaço livre. O processo vai se repetir até que todos os arquivos estejam com seus volumes determinados. Se não houver volume com espaço livre para algum arquivo, o script irá encerrar a execução reportando o erro “NO_VOLUME_FOUND_FOR_FILE”.
  • Se a base de destino existe, então ele irá alocar os arquivos no mesmo diretório que os arquivos existentes (mapeando através do nome lógico do arquivo). Se houver um arquivo a mais, ele irá escolher um dos diretórios usados pela base aleatoriamente para alocar o novo arquivo. Isso poderá resultar em erros de espaço retornados pelo comando de RESTORE, já que o cmdlet assume que se a base existe, ela está no melhor local possível e, portanto, não valida o espaço. Se isto ocorrer, você pode usar o parâmetro “NoUseCurrentFilesFolder” para forçar o cmdlet a usar o algoritmo anterior, mesmo para a base existente:

Por padrão, o script irá manter as permissões, caso a base exista. Antes de sobrescrever a base, as permissões, roles e seus membros, serão lidas e salvas na memória. Após o restore, as permissões serão aplicadas na base restaurada. Para desativar esse comportamento, utilize o parâmetro “-KeepPermissions $false”

Exemplo 2: Cópia simples com execução de scripts

Um das minhas features favortias deste cmdlet é a capacidade de executar scripts após o restore. Isso é útil quando existe uma série de scripts que o responsável pela base precisa que seja executado sempre que o restore for feito. O Parâmetro “-PostScripts” aceita um Array de strings onde cada string especifica um comando SQL, um arquivo ou um diretório contendo scripts para serem executados. Cada script é executado na ordem em que foi especificado, e no caso de diretórios os scripts serão executados na ordem do nome do arquivo. No exemplo acima, a ordem será:

  1. O script SQL
  2. Arquivo Script.sql
  3. Arquivos  no diretório “MeuBanco”, ordenados pelo nome (seguindo as regras de ordenação do Windows)

Se um script falhar, por padrão, a execução dos scripts se encerrará e o erro do script será logado. Você pode controlar esse comportamento usando o parâmetro “–PostScriptsPolicy”. Este parâmetro indica o que o cmdlet irá fazer quando o script resultar em erro. Para ignorar o erro e executar o próximo script, especifique o valor “SkipErrors”.

Você pode se perguntar se isso não representaria um risco, pois o script pode conter código malicioso, que prejudique outras bases ou mesmo a instância. Para evitar isto, o cmdlet aceita o parâmetro “UseLimitedUser”. Com este parâmetro, Copy-SQLDatabase irá criar um login na instância de destino com permissões somente na base de destino. Assim, os scripts poderão afetar somente a base de destino (a menos que, por exemplo, a permissão de CONTROL SERVER seja garantida para a role public). Após a execução, o login/usuário que foram criados, serão deletados. O nome do login será formado pela string “CopySQLDatabaseLimited_” mais o nome da base de destino. Apesar do script gerar a senha, o comando de CREATE LOGIN é transferido a instância em texto claro e, portanto, pode estar sujeito a ataques. Versões futuras podem mudar a forma como este parâmetro é implementado.

Caso o script executado retorne um RESULTSET, o mesmo será exibido no error log, linha por linha, o que pode encher o log do cmdlet.  As próximas versões irão apresentar melhorias neste processo, permitindo maiores controles sobre os resultados gerados pelo script.

Copy-SQLDatabase possui muitas funcionalidades que iriam estender mais ainda este post. Você pode usar o comando Get-Help Copy-SQLDatabase para obter mais ajuda sobre o cmdlet e seus parâmetros. Atualmente, apenas o método Backup/Restore usando T-SQL é suportado, com algumas variações. Em versões futuras, suporte a ferramentas de backup de terceiros podem ser adicionadas, bem como outros métodos de cópia.  Antes de finalizar, deixo mais alguns recursos interessantes de Copy-SQLDatabase:

  • Logging
    Copy-SQLDatabase tem uma poderosa engine de log que permite usar arquivos e até scripts powershell como destino das mensagens de log gerada. Há um modo especial para uso com o SQL Server Agent, devido ao modo como ele lida com logs e resultados.
  • Arquivos
    Apesar do cmdlet tentar escolher o melhor local dos arquivos, podem existir casos onde ele erre ou não tenha as permissões suficientes. Alguns parâmetros permitem especificar manualmente o mapeamento dos arquivos, como se estivesse usando a cláusula MOVE. Também, é possível especificar filtrar volumes e ainda especificar quais volumes são permitidos para logs e para dados.
  • Fonte do Backup
    Além de permitir que o backup em tempo real seja feito, o cmdlet permite usar um backup existente. Também, é possível forçar que a base de origem fiquem em READ_ONLY antes que o backup seja feito. Isto pode ser útil em migrações. Ainda, o cmdlet permite que um script T-SQL customizado de backup seja especificado.
  • Destino
    Além da execução de scripts no destino, o cmdlet fornece opções como colocar a base em RECOVERY SIMPLE, ou mesmo fazer o backup da base de destino antes que a base seja sobrescrita

Copy-SQLDatabase, que ainda está na versão BETA, realmente pode ser um grande ferramenta e poupar boa parte do seu trabalho, permitindo que você concentre seus esforços em outros projetos. O mesmo já foi usado, inclusive, para migrar um ambiente de produção, onde a origem era uma instância standalone e o destino uma instância em cluster, utilizando mounts points, o que reforça o potencial. Alguns detalhes desta migração podem ser conferidos neste post.

O módulo CustomMSSQL está publicado no GitHub, portanto você pode melhorá-lo ou mesmo reportar bugs. Já existem alguns issues regitrados e você pode acompanhar as correções e melhorias implementadas, bem como fazer sugestões.

Haverão outros posts falando sobre Copy-SQLDatabase e outros cmdlets do módulo CustomMSSQL. Mas você pode usar a documentação do mesmo para aprender mais. Até a próxima!

[]’s
Rodrigo Ribeiro Gomes

Um bug no SSMS ao exibir Linked Servers?

Olá, caro leitor!

Após um breve período de descanso, estou retornando ao blog e espero que esse ano possa estar mais ativo, trazendo mais conteúdo!

Resolvi começar por uma situação que ocorreu há pouco tempo e apesar de não ser algo crítico, achei bastante interessante!

Linked Server! Este é o nome de um recurso muito interessante no SQL Server que permite acessar diversas fontes de dados OLE DB a partir de uma instância SQL. Muito útil para acessar outras instâncias SQL,  arquivos excel, Active Directory, etc. Assim como a maioria das coisas no SQL Server, os Linked Servers podem ser criados de, no mínimo, duas maneiras:

  1. Via código T-SQL usando a procedure de sistema sp_addlinkedserver
  2. Via SQL Server Management Studio (interface gráfica), clicando com o botão direito em “Server Objects > Linked Servers”, e escolhendo a opção “New Linked Server”

Na maior parte do tempo eu uso a interface gráfica, por comodidade. Uso muito a interface gráfica sim (pois sou adepto da praticidade e usabilidade), e uso inclusve para checar as propriedades de algum linked server, quando preciso.  Ao clicar em propriedades é possível ver uma tela semelhante a esta:

image

 

Este linked server foi criado no SQL SERVER 2016 CTP 3.3 e aponta para a própria instância onde foi criada. Note que os campos que mostram as propriedades do Linked Server não nos revelam isto. Apenas o nome do provider OLE DB é mostrado: Microsoft OLE DB Provider for SQL Server. Bom isto é comportamento muito estranho, já que estas propriedades existem e algumas estão com valores. Isto é o que mostra a DMV “sys.servers” desta instância:

 

image

A coluna “data_source” contém o valor “localhost\sql16” e este valor não é exibido na interface. Para comprovar que a interface exibe adequadamente estes valores, eu criei um segundo Linked Server, com uma pequena diferença que irei mostrar mais adiante. Segue o script:

 

E eis a tela:

image

 

Note que desta vez, as informações são exbidas adequadamente. Óbvio que por razões de simplicidade, eu apenas estou considerando a informação “Data Source”, mas o que estou mostrando aqui é válido para todas as outras.

Bom, mas por que será que, na primeira imagem, estas informações não aparecem? A resposta está no provider. Repare que na primeira imagem, o provider é o “Microsoft OLE DB Provider for SQL Server”. Na segunda, o provider é o “SQL Server Native Client 11.0”. Providers OLE DB (e ODBC) são coisas que durante um bom tempo eram um bicho de sete cabeças sentado sob trono do rei Daburá, cantando “Tá Tranquilo, Tá favorável”. Eu tinha pavor só de ouvir falar… Mas em suma, providers são apenas DLLs chamadas pela engine do OLE DB. São essas DLLs quem, de fato, se conectam com a fonte de dados, obtém os dados, e os apresenta de um forma padronizada para o OLE DB. Isso permite que uma aplicação possa facilmente mudar a fonte de dados sem mexer no código, e isso é incrivelmente demais.

Os providers possuem uma espécie de identificação que é globalmente única! Essa identificação é nada mais do que um GUID. Há também um identificador mais amigável, chamado “ProgID”.  É esse identificador que usamos ao criar o linked server. No código acima, o ProgID que usei foi “SQLNCLI11”. Você pode ver a lista de ProgIDs usando a procedure “sp_enum_oledb_providers” ou no SSMS, caminho “Server Objects > Linked Servers > Providers”.

Tá, mas o que isso tem a ver!? Calma lá…. Te prometo que tudo irá fazer sentido já já.  A procedure “sp_addlinkedserver” aceita um “ProgID” especial. Na verdade, não é nem um “ProgID” existente (ele não é retornado pela procedure “sp_enum_oledb_providers”, e muito menos é exibido no direótrio “Providers” do SSMS). Este ProgID especial é o “SQLNCLI”. A documentação de “sp_addlinkedserver” destaca o seguinte, para o parâmetro @provider:

[ @provider = ] provider_name

Is the unique programmatic identifier (PROGID) of the OLE DB provider that corresponds to this data source. provider_name must be unique for the specified OLE DB provider installed on the current computer. provider_name is nvarchar(128), with a default of NULL; however, ifprovider_name is omitted, SQLNCLI is used. (Use SQLNCLI and SQL Server will redirect to the latest version of SQL Server Native Client OLE DB Provider.) The OLE DB provider is expected to be registered with the specified PROGID in the registry.

 

O ProgID SQLNCLI é o padrão e é usado sempre que o valor do parâmetro @provider é omitido. Porém, por debaixo dos panos, o que o SQL Server faz quando o linked server é executado, é selecionar a versão mais recente do Native Client disponível, o que é ótimo. Porém, o SSMS parece não entender muito bem esta regra.  Aqui está o “provider_name” de cada um dos linked servers criados anteriormente:

image

 

No Linked Server “THE_SQL_TIMES”, o que não exibe as informações corretamente no SSMS, o provider é justamente o SQLNCLI. No segundo, o provider é o “SQLNCLI11”. E eu ainda criei um terceiro, cujo o provider é fornecido pelo pacote Microsoft Data Access Components (ProgID = MSDASQL):

 

 

image

 

E, lá está o valor da propriedade! O que parece acontecer é que a interface se atrapalha quando vai exibir os dados e o provider é o “SQLNCLI”. Eu ativei um trace ao usar a interface e percebi que a interface faz as seguintes ações (um resumo):

  1. Obtém as informaçoes do Linked Server, lendo os dados da sys.servers
  2. Executa a procedure “sp_enum_oledb_providers”

Ao que tudo indica, ao perceber que o provider retornado no passo 1 não exite na lista retornado no passo 2, algo acontece e a interface simplesmente não exibe as informações! A solução é fácil, e conforme já mostrei anteriormente, basta criar o linked server com o ProgID SQLNCLIXX, onde XX é a versão correspondente instalada no servidor onde a instância está. Claro, isto se você deseja usar o Native Client como provider.

Extendendo a brincadeira

Bom, para deixar as coisas com mais um pouco de graça, relembre a tela em que as informações não são exibidas:

image

Eu ainda não estava convencido do porquê o texto “Microsoft OLE DB Provider for SQL Server” era exibido no campo “Provider:”. Bom, para descobrir o ProgID associado com este nome, você pode pensar: “Olhe na sys.servers”. Mas, conforme mostrei anteriorment,e a “sys.servers” nos mostra que o provider é o SQLNCLI… E sabemos que como o SQLNCLI, o nome exibido é “SQL Server Native Client ” + a versão.  A procedure “sp_enum_oledb_providers” nos revela qual é o ProgID:

image

 

Perceba que no resultado, a coluna “Provider Description” fornece o valor que visualizamos na descrição. O valor corresponde ao ProgID (que está na coluna “Provider Name”) é “SQLOLEDB”, que é uma implementação depreciada fornecida pelo pacote Microsoft Data Access Components (MDAC). Bom, a minha suspeita era de que a interface iria exibir o primeiro da lista… E a minha única forma de comprovar isto foi deletando o provider pelo registro, coisa que, eu fiz na minha máquina de trabalho e vou repetir de novo em minha máquina pessoal, e nem preciso mencionar que você não precisa fazer isso em sua honrada produção, homologação e desenvolvimento, ok? Os passos são os seguintes, e você pode fazer por sua própria conta e risco:

    1. Abra o regedit.exe
    2. Clique na seguinte chave: HKEY_CLASSES_ROOT\CLSID
      Aqui contém aqueles identificadores globais das interfaces do COM. Os providers OLE DB são interfaces do COM, e como você é uma pessoa esperta, já entendeu o que vai fazer né!?
    3. Pegue o valor da coluna “Parse Name” e use o FIND (F3 ou vá pelo menu Editar) do regedit para procurá-lo.
    4. Faça um backup, usando o comando de exportar (File -> Export)
    5. Utilize sua religião, faça suas preces, e delete a chave inteira. Você vai precisar alterar o owner da chave e reaplicar as permissões para todas sub-chaves. Aqui segue um exemplo da chave que irei deletar:

image

 

Bom, após deletar a chave, a “sp_enum_oledb_providers” passou a retornar o seguinte:

image

E voilà:

image

O Provider mudou… Mas, este infeliz autor, ainda não estava satisfeito e resolveu fazer a mesma coisa com o SQLNCLI11. E a “sp_enum_oledb_providers” retornou após eu repetir as etapas acimas para o SQLNCLI11:

image

E a tela:

image

 

Sim! As suspeitas se confirmaram! Agora eu estava convencido! O SSMS parece usar o primeiro provider da lista. E por algum motivo, o que me parece ser uma espécie de “bug” do SSMS, ele não exibe as informações do Linked Server!

Bom, isto não é um problema que vá parar seu ambiente ou impedir que você use o Linked Server e talvez, por esse motivo, nunca recebeu uma atenção, e provavelmente nunca irá receber. Mas, para aqueles que são curiosos e gostam de se aventurar nos porquês das coisas, está aí a resposta, caso um dia você tenha esta curiosidade!

 

Fontes  e Referências:

 

Ops, e antes de ir, não perca o primeiro SQL Saturday do Ano, no Brasil, em JoinVille! É o SQL Saturday #488. Você pode se inscrever e obter mais informações acessando o link: http://www.sqlsaturday.com/488/eventhome.aspx