THE SQL TIMES

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

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

After SQL Saturday 469 (Delayed) e 2015 Review!

Salve amigos!

2015 foi um ano incrível para mim, apesar da atual situação política, econômica e cultural do país. Por isso, eu resolvi escrever um post especial, sem conteúdo técnico, para compartilhar o que fez de 2015 tão bom assim.

O SQL Saturday 469

Primeiro, e com bastante atraso, vou falar do SQL Saturday 469, que aconteceu no dia 21 de novembro de 2015, na faculdade Projeção, em Taguatinga (Brasília). O evento estava excelente, com vários palestrantes de fora, e como sempre, a organização deu show.  O meu muito obrigado ao Luti pela escolha da apresentação e por se dedicar a um evento como o SQL Saturday e nos moldes que foi. Novamente, eu sempre ressalto a importância da participação nesses eventos, seja como palestrante, voluntário ou apenas espectador. É uma chance para entrar para o mundo SQL Server, ou, se você já vive no mundo SQL Server, é uma oportunidade de elevar seus conhecimentos e tirar todas as dúvidas, pois os palestrantes possuem um alto nível técnico e com certeza você não irá se arrepender. Além disso, você vai conhecer outras pessoas da área, e que já trabalham algum tempo, e pode ser que você consiga uma ótima oportunidade para sua carreira. Então, desfrute do SQL Saturday e aproveite todo o potencial que o evento pode oferecer a você!

No blog do Luti, tem um review do evento e um link para as fotos! Acesse em: http://luticm.blogspot.com.br/2015/11/quick-review-sqlsat-469-brasilia.html

Em abril, vai rolar o SQL Saturday 488, em Joinville, e já estou me preparando para ir, seja como palestrante ou voluntário! Se você puder ir, então, vá! O site do evento é este: http://www.sqlsaturday.com/488/EventHome.aspx

 

Participação na Comunidade

 

Este ano também participei do SQL Saturday 424, em São Paulo, como palestrante e espectador, apresentei no Virtual PASS, participei de grupos de estudos (apresentando e assistindo) e conseguir ajudar mais pessoas em fóruns, além de ter postado mais no blog (Uauuu!). Eu sempre me preocupo em retribuir à comunidade técnica pois foi graças a ela, onde aprendi toda a base que me ajuda até hoje a entender e continuar aprendendo novas tecnologias. Eu sempre vou reservar algum tempo para me dedicar a comunidade técnica, pois serei eternamente grato à esses que um dia se dedicaram também!

Estudos

Todo ano, eu sempre fico preocupado se vou deixar de seguir o meu ritmo dos anos anteriores em relação aos estudos, e estou deixando 2015 com a sensação de “missão cumprida”. Foi um dos anos que mais aprendi novas tecnologias, e é claro, muito, mas muito mesmo sobre SQL Server e outros produtos Microsoft, e que em breve estarei compartilhando aqui. Powershell se consolidou na minha carreira e não largo mais! Também, finalmente consegui parar e estudar um pouco mais de Assembly e confesso que estou muito empolgado em descer mais o nível.  Para este ano ficou faltando mais investir tempo em Azure, Linux, Big Data e Machine Learning, que são tecnologias do momento e têm feito a diferença em muitos negócios! Mas nunca é tarde, e quem sabe no próximo ano eu não me envolva mais! Para este ano, o destaque foi para o que aprendi sobre CPU e Zabbix! Tudo isso será compartilhado futuramente aqui no blog!

E então…

Bom, este ano foi realmente incrível e espero que 2016 venha com tudo de bom em dobro. Eu irei me ausentar um pouco da comunidade técnica até meados de fevereiro ou março, pois preciso cuidar um pouco mais da minha saúde e aproveitar um pouco da vida. Mas estou planejando um 2016 muito maior que 2015, com mais conteúdo útil e mais participação!

Fica aqui o meu abraço, uma feliz natal, feliz 2016 e boas festas à todos!

Apresentando CustomMSSQL, Copy-SQLdatabase e SCRIPT STORE: Versão BETA

Há muito tempo, ingressei no mundo de tecnologia estudando HTML. Desde então, aprendi muitas coisas na área de TI e não parei por aí. Bom, o que isso tem a ver com esse post? Simples: A comunidade, não só de SQL, mas de tecnologia em geral, é uma das coisas mais importantes de minha carreira.

Pensando em retribuir isso, há algum tempo eu venho mantendo uma série de scripts feitos em powershell que têm me ajudado a gerenciar o ambiente SQL. Eu gostei bastante dos resultados que resolvi publicá-los. E tudo isso será de graça, free, 0800, para sempre! Para tentar entregar algo mais organizado e fácil de aprender, eu também estou lançando a SCRIPT STORE. A script store é um repositório de tudo que é tipo de script que eu irei publicar e manter atualizado. Em breve, espero que ela esteja bem, mas bem cheia mesmo.

Já existem dois scripts publicados: O módulo CustomMSSQL e a procedure sp_WhoIsAuthorized. Eu já fiz muitos testes com estes dois scripts, tanto que já possui mais de 1 ano de vida. E, eu venho usado em meu dia-a-dia como DBA. Estes scripts são exemplos de coisas que eu sinto falta no SQL Server, e espero que você possa me ajudar, ou melhor, possa ajudar a todos, fazendo destes códigos algo estável e útil para muitos ambientes, e claro, sempre e sempre free!

Hoje eu vou dar destaque para o módulo CustomMSSQL. Este módulo disponibiliza vários cmdlets para lidarmos com o SQL Server. Por exemplo, temos o Get-SQLAgentOptions que traz as configurações do SQL Agent que estão salvas no registro. Há também o Send-SQL2Zabbix, que é um cmdlet extremamente poderoso para quem quer integrar o SQL Server com o Zabbix. Este último eu já estou usando em um ambiente que estou trabalhando e tenho tido resultados incríveis. Em breve posto mais sobre ele.

Eu quero inaugurar este módulo falando, na verdade, de um cmdlet que desenvolvi e têm sido meu xodó e me ajudado bastante: Copy-SQLDatabase. Como o nome já diz, este cmdlet serve para copiar bases SQL. Vou pegar o exemplo da documentação do cmdlet que já está disponível na Script Store:

Bom, conforme descrito na documentação, este exemplo é bem simples: ele copia a base MyDB, que está na instância “ProdServer\Inst01” para a instância “DevInst” com o nome, também, de “MyDb”.

O processo é bem simples e se você já administra instâncias SQL há algum tempo, já estará familiarizado: Ele faz um BACKUP da base na instância de origem, e um RESTORE na instância de destino. Simples. A principal diferença, e minha preferida, é que eu não preciso me preocupar mais em determinar em quais discos a base deverá ser restaurada. O cmdlet irá fazer isso por conta própria. Graças à flexibilidade do powershell, o script consegue determinar os discos disponíveis no servidor onde a instância de destino está. Isso é perfeito para a maioria das cópias entre produção e desenvolvimento.

Log coletado de um caso real

Exemplo do início do log de Copy-SQLDatabase. Este log foi de um uso em real, para copiar a base de uma instância de produção para outra, em cluster.

Quando a base não existe, o algoritmo que ele usa tem uma lógica bem simples: Maiores primeiros. Isto significa que, partindo do maior do arquivo, o cmdlet tenta eleger em qual volume ele irá alocar o mesmo. Após escolher, ele subtrair a quantidade de espaço do volume, e checa o próximo maior arquivo. Ele vai fazendo até que todos os arquivos tenham sido mapeados para um volume. Se algum arquivo não pode ser mapeado, por não haver um volume com espaço suficiente, por exemplo, então ele encerra a execução e exibe o erro.

Se a base de destino já existe, por padrão, o script vai tomar um caminho diferente. Ao invés de realocar os arquivos em volumes novos, ele usa os diretórios em que os arquivos da base existente estão. Ele associa os arquivos pelo nome lógico. Se o arquivo não existir  na base de destino (caso tenha sido adicionado desde que a base foi copiada, por exemplo) ele escolhe um dos diretórios aleatoriamente. O cmdlet tem esse comportamento pois ele assume que a base de destino já está alocada no melhor lugar possível. Você controlar esse comportamento através de parâmetros do cmdlet. No caso da base existir também, antes de substitui-la, usuários, permissões e roles são “backupeados” para depois serem restaurados.

Exemplo do log de Copy-SQLDatabase, quando vai fazer o backup na origem e determinar os arquivos disponíveis. Este log foi de uma uso em real, para copiar a base de uma instância de produção para outra, em cluster.

Exemplo do log de Copy-SQLDatabase, quando vai fazer o backup na origem e determinar os arquivos disponíveis. Este log foi de um uso em real, para copiar a base de uma instância de produção para outra, em cluster.

Bom,  há muita, mas muita coisa que este cmdlet é capaz de fazer, e em futuros posts irei dar mais dicas e mostrar mais funcionalidades. Por hora, destaco alguns parâmetros que potencializam Copy-SQLDatabase:

  • UseRecent, RecentFileMask e RecentBase
    Estes parâmetros permitem que você especifique um arquivo existente como fonte do RESTORE, ao invés do cmdlet executar um BACKUP novo. Você pode controlar quão recente o arquivo deve ser e o filtro para listar os arquivos. O cmdlet irá procurar o arquivo no diretório especificado por “BackupFolder”.
  • DestinationDatabaseBackup
    Faz o backup da base de destino antes de substitui-la. Você deve informar o caminho do backup. Isso é útil em situações que necessitem guardar uma base que será sobrescrita.
  • ForceSimple, Replace, NoRecovery
    Coloca a base em SIMPLE após restaurá-la, usa a opção REPLACE e usa a opção NORECOVERY, respectivamente.
  • AllowedVolumes,VolumesForData, VolumesForLog
    Permite especificar quais volumes serão usados. AllowedVolumes restringe os volumes que serão considerados. Você pode usar caracteres coringa como “*”. VolumesForData e VolumesForLog permite que você especifique em quais volumes o cmdlet deve mapear arquivos de dados e arquivos de log, respectivamente. Isso é bem útil quando você que restaurar bases na produção. Estes parâmetros não têm efeito quando a base já existe e o diretório dos arquivos existentes serão usados.
  • PostScripts, UseLimitedUser
    Este e um dos meus favoritos. Muitas solicitações de cópias de produção para desenvolvimento incluem a execução de scripts, como por exemplo, um UPDATE para trocar as senhas para “123456”. Pensando na diversidade destas solicitações, você pode especificar um array de código T-SQL para ser executado na base após o restore. Você pode especificar diretórios, comandos T-SQL ou nome de arquivos. O parâmetro UseLimitedUser faz com que os scripts sejam executados com um usuário que só irá ter acesso a base restaurada. Isso pode evitar que scripts maliciosos afetem a instância inteira. Por exemplo, se o usuário colocar um SHUTDOWN no script, ele não irá funcionar.  O script apenas cria um login/usuário único na instância/base, concede permissões de db_owner na base de destino somente, e ao final deleta ele.
  • LogTo e LogLevel
    Com estes parâmetros você pode controlar  quantidade de Log que é gerado pelo script. O padrão é o modo “DETAILED” onde ele mostra uma série de informações a respeito do progresso do script. Pode ser útil para entender erros que podem acontecer,  ou mesmo ver para onde os arquivos serão mapeados. Com  LogTo, você controla para onde o log será feito. Você pode especificar um array de arquivos. O padrão é “#” que significa que o script irá usar “write-host” para logar as mensagens.

Apesar de estar na versão beta, eu já tenho usado este script para copiar diversas bases, todos os dias, de produção para homologação, e usando, além dos parâmetros acima, muitos outros disponibilizados. Recentemente eu usei o script para migrar cerca de 20 bases distribuídas em 100GB de uma instância standalone para uma instância em cluster, em produção. Apesar de ser pouco, eu poupei bastante trabalho e precisei apenas observar.

Exemplo log de Copy-SQLDatabase, quando vai determinar os volumes. Este log foi de uma uso em real, para copiar a base de uma instância de produção para outra, em cluster.

Exemplo log de Copy-SQLDatabase, quando vai determinar os volumes. Este log foi de uma uso em real, para copiar a base de uma instância de produção para outra, em cluster.

 

Exemplo do log de Copy-SQLDatabase, quando, vai determinar em quais volumes ele irá alocar o arquivo. Este log foi de uma uso em real, para copiar a base de uma instância de produção para outra, em cluster.

Exemplo do log de Copy-SQLDatabase, quando, vai determinar em quais volumes ele irá alocar o arquivo. Este log foi de uma uso em real, para copiar a base de uma instância de produção para outra, em cluster.

Bom, espero que o script seja útil e qualquer dúvida, sugestão e problema basta enviar um email para “rodrigo@thesqltimes.com” ou “rodrigorigomes@gmail.com” ou enviar em um comentário deste post.

Baixe o módulo CustomMSSQL Beta em: http://scriptstore.thesqltimes.com/custommssql/sobre-custommssql/custommssql/ 

Instância DEFAULT e conectividade não default – Parte 3 (Final)

Olá! Finalmente, chegamos ao último post sobre conectividade e instância DEFAULT! Na parte 1 e parte 2 eu mostrei como as configurações de conectividade podem resultar em timeouts e delays na conexão. Para encerrar, tem um outro caso bem interessante: quando uma instância nomeada está rodando na porta ou pipe default, em um servidor com uma instância DEFAULT rodando em outra porta. Como você já deve esperar, este é um caso que pode gerar problemas mais sérios! Vamos lá!?

Cenário Outra Instância na porta 1433

Bom! Já vimos que uma instância DEFAULT aguardando conexões em portas ou pipes diferente dos valores padrões já pode trazer muitos problemas. Agora, indo contra todos os exemplos anteriores, vamos colocar uma instância nomeada rodando na porta 1433 e no final você terá um servidor com duas instâncias:

  • A instância DEFAULT está em uma porta diferente da default (1436 em nosso exemplo)
  • A instância nomeada (SQL08R2) está na 1433

Eu acho que um ambiente assim não faz sentido, mas penso que podem haver certas situações que acabem resultando nesta configuração. Esta é uma outra discursão e não vêm ao caso. Bom, chega de blá blá e vamos ao que interessa. Vou executar um script simples: Ele se conecta em cada instância e mostra o nome da mesma usando a variável @@SERVERNAME. Bom, vamos fazer o teste na instância DEFAULT:

Como este é uma teste bem trivial apenas executar o sqlcmd basta. Olha qual foi o resultado pra mim:

Resultado da conexão na instância DEFAULT

 

Nossa! Que mer*@$$%! hein!?  Dessa vez não houveram delays, mas aconteceu algo pior. Você se conectou na instância errada! Isso pode representar um perigo se estas duas instâncias têm, por exemplo, duas bases idênticas. Depois de tudo o que vimos anteriormente, fica fácil dizer o que houve: aquela tentativa inicial na 1433 foi feita, e como a instância SQL08R2 está escutando nesta porta, o client acabou se conectando na instância nomeada ao invés de se conectar na instância DEFAULT.

Conclusão

Diante disto, o que podemos deixar para a lição é: Sempre deixe uma instância DEFAULT na porta e pipe defaults, a menos que você tenha total controle de como as aplicações vão se conectar nela. Imagie este problema em aplicações como o SSIS que, dependendo do pacote, abre várias conexões ao mesmo tempo… O próprio SSMS abre muitas conexões a medida que vamos usando a interface, o que pode tornar tarefas simples um pouco mais demoradas. Isso sem contar os possíveis timeouts.

 

Antes de ir, deixo aqui alguns links úteis que falam mais sobre este problema e outros de conectividade:

 

 

[]’s
Rodrigo Ribeiro Gomes

 

Registre-se no SQL Saturday 469 e garanta sua vaga para!

Registre-se no SQL Saturday 469 e garanta sua vaga para!