iMaster Developers

Wagner Crivelini

Wagner Crivelini

Consultor Sênior na Microsoft, na área de Data Insights para América Latina. Especialista em bancos de dados, é colunista em diversos portais de TI do Brasil e do exterior, com mais de 100 artigos técnicos publicados. É também co-produtor do DatabaseCast, primeiro podcast brasileiro sobre bancos de dados.
  • Publicou
    87
    Artigo(s)
    book
  • Visualizados
    756900
    Vezes
    eye
  • Desde
    2010
    clock
awardArtigos Publicados
Wagner Crivelini
Data
O Caso das Consultas Lentas no Synapse

Um dos componentes do Azure Synapse Analytics é o recurso conhecido como SQL Pool, que funciona, em linhas gerais, como um grande servidor SQL. O Synapse SQL Pool usa uma arquitetura de Processamento Paralelo Massivo (ou MPP, na sigla em inglês), que lhe permite oferecer uma capacidade de processamento extremamente alta. Mas é importante lembrar…

Wagner Crivelini
SQL Server
Análise de Grafos no Azure SQL DB

O uso de bancos de dados de grafos continua crescendo rapidamente, mas ainda assim a grande maioria dos profissionais de TI desconhece os conceitos envolvidos. Hoje existem vários produtos desta categoria, tais como Azure Cosmos Gremlin API e NEO4J (clique aqui para informações sobre o mercado de bancos de dados de grafos). E existem também…

Wagner Crivelini
MySQL
O Caso do Índice Temporário

Este caso aconteceu na avaliação de um script SQL onde um simples caractere adicional no nome de um índice acabou causando muita discussão. O fato é que a documentação é um tanto vaga no quesito nomenclatura de índices, dando margem a entendimentos diferentes. Este artigo apresenta o estudo que foi feito para esclarecer a situação….

Wagner Crivelini
Banco de Dados
Azure SQL DB: Trabalhando com Listas e Arrays (parte 2)

No artigo anterior (link) falei sobre a leitura de listas de valores em arquivos JSON usando recursos do Azure SQL DB. Agora é a vez de tratar de listas de valores em arquivos texto (TXT, CSV etc.). Arquivos Texto e Listas Nos exemplos que apresentarei a seguir, eu uso um arquivo CSV com o mesmo…

Wagner Crivelini
SQL Server
Azure SQL DB: trabalhando com listas e arrays (Parte 1)

Listas, arrays, matrizes, vetores. Independente do nome que você prefira usar, cedo ou tarde vai ter que lidar com estes tipos de estrutura de dados. Estas não são estruturas comuns no mundo relacional, porém temos que ter em mente que hoje a diversidade de formatos e estruturas é uma regra no mundo corporativo. Mais que…

Wagner Crivelini
SQL Server
Tabelas Temporais Particionadas - Criando Auditoria de Dados em Tabelas Grandes

Desde a versão 2016 do SQL Server está disponível o recurso para auditoria automática de dados através das Tabelas Temporais.

Wagner Crivelini
Data
Entendendo os Recursos de Criptografia do AZURE SQL Database

Recentemente precisei apresentar para um cliente um material com noções básicas dos recursos de criptografia disponíveis no AZURE SQL Database.

Wagner Crivelini
SQL Server
Bate-bola com Grafos e SQL Server Parte 3 – Visualizando Dados

Desta vez o enfoque é na análise de dados, mais especificamente a visualização dos grafos que foram criados. Eu prefiro começar a conversa com o porquê e depois falo do como. Ou seja, começo mostrando para que serve a visualização dos grafos e, na sequência, apresento como construir um dashboard simples destes grafos. Analisando Dados…

Wagner Crivelini
SQL Server
Bate-bola com Grafos e SQL Server Parte 2 – Implementando o Modelo

Neste artigo dou sequência no estudo de grafos usando a base de dados European Soccer Database, publicada por Hugo Mathien no KAGGLE. Desta vez vou tratar da implementação do modelo de grafos definido no artigo anterior usando o SQL Server 2019. Apresento também algumas consultas e análises sobre estes grafos. Criando as Tabelas Definido o…

Wagner Crivelini
SQL Server
Bate-bola com Grafos e SQL Server Parte 1 – Definindo o Modelo

É espantosa a popularização que as novas tecnologias de dados alcançaram. A utilização de Grafos para análise de dados e o SQL Server…

visualizando 10 de 87
Publicidade
\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003C\u002Ftbody\u003E\r\n\u003C\u002Ftable\u003E\r\n\u003Cspan style=\"font-weight: 400;\"\u003EO output que vai gerar para a leitura do arquivo JSON apresentado na Tabela 1 é:\u003C\u002Fspan\u003E\r\n\u003Ctable\u003E\r\n\u003Ctbody\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cb\u003Ekey\u003C\u002Fb\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cb\u003Evalue\u003C\u002Fb\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cb\u003Etype\u003C\u002Fb\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EOrderNumber\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E1\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ECustomer\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E1\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAdress\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E[           {      \"Name\": \"Casa\",            \"Street\": \"Rua 5, no 42\",   ...  }      ]\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E4\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EProductID\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E[ \"AAF\",\"AAR\",\"AAS\",\"AAT\",\"AAV\",\"AAW\" ]\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E4\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003C\u002Ftbody\u003E\r\n\u003C\u002Ftable\u003E\r\n\u003Cspan style=\"font-weight: 400;\"\u003ECaso se deseje lidar com o esquema interno do JSON, substituímos o SELECT da linha 24 por uma declaração que reflita este esquema, como vemos a seguir.\u003C\u002Fspan\u003E\r\n\u003Ctable\u003E\r\n\u003Ctbody\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E01\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E02\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E03\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E04\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E05\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E06\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E07\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E08\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E09\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E10\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E11\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E12\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E13\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E14\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E15\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E16\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E17\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESELECT\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E J\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EOrderNumber\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E J\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003ECustomer\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E P\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003Evalue\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAS\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E ProductID\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E A\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EName\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E A\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EStreet\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E A\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003ECity\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E A\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EState\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EFROM\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E  \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EOPENJSON \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E @json\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E' window.__SERVER_VARS__ = {"applicationRestUrl":"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-json","applicationBaseUrl":"https:\u002F\u002Fadmin.imasters.com.br"}\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E \u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EWITH \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E  OrderNumber\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E200\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E'$.OrderNumber'\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E \u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E Customer   \u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E200\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E'$.Customer'\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E Adress     \u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003ENVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EMAX\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E'$.Adress'\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAS\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EJSON\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E ProductID  \u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003ENVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EMAX\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E'$.ProductID'\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAS\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EJSON\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAS\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E J\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003ECROSS\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAPPLY\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EOPENJSON \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJ\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EProductID\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E' window.__SERVER_VARS__ = {"applicationRestUrl":"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-json","applicationBaseUrl":"https:\u002F\u002Fadmin.imasters.com.br"}\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E  P\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003ECROSS\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAPPLY\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EOPENJSON \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJ\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAdress\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E  \u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EWITH \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E  \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EName\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E         \u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E200\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E'$.Name'\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E \u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E Street       \u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E200\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E'$.Street'\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E \u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E City         \u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E200\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E'$.City'\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E \u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EState\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E        \u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E200\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E'$.State'\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E \u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAS\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E A\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003C\u002Ftbody\u003E\r\n\u003C\u002Ftable\u003E\r\n\u003Cspan style=\"font-weight: 400;\"\u003EObserve que a primeira chamada OPENJSON define a estrutura principal do arquivo, estabelece as colunas OrderNumber, Customer, Adress e ProductID. Nessa definição, as duas últimas colunas foram classificadas como novos JSONs, de modo que se pudesse expandir seu conteúdo.\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EAcontece que o tratamento dessas duas colunas “JSON” ocorre de forma distinta. Apesar de ambas invocarem o operador OPENJSON, a primeira delas, Adress, é uma lista de JSONs e por isso foi expandida em novas colunas, do mesmo modo que se tratou a estrutura principal.\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003ENo caso da coluna ProductID, trata-se de uma lista de valores associada à marcação “ProductID”. Isto requer um tratamento diferenciado, embora tenha solução simples e elegante. Aqui basta usar o operador OPENJSON e na cláusula SELECT apontar para a lista de valores usando a sintaxe “\u003C\u002Fspan\u003E\u003Ci\u003E\u003Cspan style=\"font-weight: 400;\"\u003EMeuAlias.value\u003C\u002Fspan\u003E\u003C\u002Fi\u003E\u003Cspan style=\"font-weight: 400;\"\u003E”. No exemplo acima, usei o alias “P”.\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EO output dessa nova consulta é uma tabela de valores.\u003C\u002Fspan\u003E\r\n\u003Ctable\u003E\r\n\u003Ctbody\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cb\u003EOrderNumber\u003C\u002Fb\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cb\u003ECustomer\u003C\u002Fb\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cb\u003EProductID\u003C\u002Fb\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cb\u003EName\u003C\u002Fb\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cb\u003EStreet\u003C\u002Fb\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cb\u003ECity\u003C\u002Fb\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cb\u003EState\u003C\u002Fb\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAF\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ECasa\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua 5, no 42\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESão Paulo\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESP\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAF\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EEscritorio\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua D Pedro, no 500\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERio de Janeiro\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERJ\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAR\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ECasa\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua 5, no 42\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESão Paulo\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESP\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAR\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EEscritorio\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua D Pedro, no 500\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERio de Janeiro\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERJ\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAS\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ECasa\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua 5, no 42\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESão Paulo\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESP\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAS\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EEscritorio\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua D Pedro, no 500\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERio de Janeiro\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERJ\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAT\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ECasa\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua 5, no 42\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESão Paulo\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESP\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAT\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EEscritorio\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua D Pedro, no 500\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERio de Janeiro\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERJ\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAV\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ECasa\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua 5, no 42\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESão Paulo\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESP\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAV\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EEscritorio\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua D Pedro, no 500\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERio de Janeiro\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERJ\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAW\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ECasa\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua 5, no 42\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESão Paulo\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESP\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAW\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EEscritorio\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua D Pedro, no 500\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERio de Janeiro\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERJ\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003C\u002Ftbody\u003E\r\n\u003C\u002Ftable\u003E\r\n\u003Ch3\u003E\u003Cb\u003EAvaliando a Performance\u003C\u002Fb\u003E\u003C\u002Fh3\u003E\r\n\u003Cspan style=\"font-weight: 400;\"\u003EDe modo geral, a performance das operações envolvendo operador OPENJSON não é boa. Para entender melhor este impacto, vamos avaliar três situações diferentes. \u003C\u002Fspan\u003E\r\n\u003Ch3\u003E\u003Cb\u003ECaso 1\u003C\u002Fb\u003E\u003C\u002Fh3\u003E\r\n\u003Cspan style=\"font-weight: 400;\"\u003EAqui consideramos o plano de execução da consulta que gerou a listagem apresentada acima. O procedimento envolve duas consultas, sendo que a segunda, que trata da formatação do JSON, responde por 96% de todo custo do processo: 0,6605. O tempo de execução foi de 01 segundo.\u003C\u002Fspan\u003E\r\n\u003Ch3\u003E\u003Cimg class=\"alignnone size-full wp-image-156777\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2022\u002F01\u002Fcaso1.png\" alt=\"\" width=\"585\" height=\"435\" \u002F\u003E\u003C\u002Fh3\u003E\r\n\u003Ch3\u003E\u003Cb\u003ECaso 2\u003C\u002Fb\u003E\u003C\u002Fh3\u003E\r\n\u003Cspan style=\"font-weight: 400;\"\u003EDesta vez vamos consultar o mesmo arquivo JSON, mas vamos desconsiderar a lista de JSONs da marcação “Adress”. A primeira parte do procedimento continua idêntica, mas segunda vai usar a seguinte declaração:\u003C\u002Fspan\u003E\r\n\u003Ctable\u003E\r\n\u003Ctbody\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E01\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E02\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E03\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E04\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E05\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E06\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E07\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E08\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E09\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESELECT\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E J\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EOrderNumber\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E J\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003ECustomer\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E P\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003Evalue\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAS\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E ProductID\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EFROM\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E  \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EOPENJSON \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E @json\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E' window.__SERVER_VARS__ = {"applicationRestUrl":"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-json","applicationBaseUrl":"https:\u002F\u002Fadmin.imasters.com.br"}\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E \u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EWITH \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E  OrderNumber\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E200\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E'$.OrderNumber'\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E \u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E Customer   \u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E200\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E'$.Customer'\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E Adress     \u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003ENVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EMAX\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E'$.Adress'\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAS\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EJSON\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E ProductID  \u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003ENVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EMAX\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E'$.ProductID'\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAS\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EJSON\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAS\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E J\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003ECROSS\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAPPLY\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EOPENJSON \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJ\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EProductID\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E' window.__SERVER_VARS__ = {"applicationRestUrl":"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-json","applicationBaseUrl":"https:\u002F\u002Fadmin.imasters.com.br"}\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E  P\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003C\u002Ftbody\u003E\r\n\u003C\u002Ftable\u003E\r\n\u003Cspan style=\"font-weight: 400;\"\u003ENeste caso, vamos converter em tabela a lista de valores da coluna ProductID. O custo da primeira consulta é exatamente o mesmo do caso anterior, porém a segunda consulta roda 50 vezes mais rápido, tendo seu custo reduzido para 0.0130 (contra 0,6605 no Caso1)!!! O tempo de execução praticamente não mudou (01 seg).\u003C\u002Fspan\u003E\r\n\r\n\u003Cimg class=\"alignnone size-full wp-image-156778\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2022\u002F01\u002Fcaso2.png\" alt=\"\" width=\"587\" height=\"441\" \u002F\u003E\r\n\r\n\u003Cb\u003ECaso 3\u003C\u002Fb\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EAgora vamos avaliar uma expansão do Caso 2. Usaremos outro arquivo JSON com mesmo esquema, porém dessa vez o campo ProductID tratará uma lista com 100 mil valores ao invés de apenas 6.\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EA única alteração no procedimento é reapontar o script para ler o arquivo “exemplo2.json”, cujo tamanho é de 811 Kb, ao invés do arquivo “exemplo1.json”, de 445 bytes.\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EObserve no plano de execução abaixo que, apesar de estar lendo um arquivo quase 2 mil vezes maior, os custos da primeira e segunda consultas são exatamente os mesmos que observamos no Caso 2! O tempo de execução subiu, mas muito pouco: apenas 06 segundos.\u003C\u002Fspan\u003E\r\n\r\n\u003Cb\u003E\u003Cimg class=\"alignnone size-full wp-image-156779\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2022\u002F01\u002Fcaso3.png\" alt=\"\" width=\"588\" height=\"439\" \u002F\u003E\r\nComentários Finais\u003C\u002Fb\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EComo vimos neste estudo, a preparação para acesso a arquivos JSON armazenados em contas de armazenamento requer alguns cuidados especiais. Porém, uma vez configurados, a leitura desses arquivos no Azure SQL DB funciona muito bem. \u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003ESobre a leitura de listas de valores em formato JSON, os dois pontos que se destacam são:\u003C\u002Fspan\u003E\r\n\u003Col\u003E\r\n \t\u003Cli style=\"font-weight: 400;\" aria-level=\"1\"\u003E\u003Cspan style=\"font-weight: 400;\"\u003EA sintaxe usada para leitura dessas estruturas é bastante simples. Basta definir a coluna como JSON, abri-la com o operador OPENJSON e apontar para seus valores com a expressão \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E“\u003C\u002Fspan\u003E\u003Ci\u003E\u003Cspan style=\"font-weight: 400;\"\u003EMeuAlias.value\u003C\u002Fspan\u003E\u003C\u002Fi\u003E\u003Cspan style=\"font-weight: 400;\"\u003E”.\u003C\u002Fspan\u003E\u003C\u002Fli\u003E\r\n \t\u003Cli style=\"font-weight: 400;\" aria-level=\"1\"\u003E\u003Cspan style=\"font-weight: 400;\"\u003EO custo de execução de consultas envolvendo listas de valores é praticamente invariável. O impacto do tamanho da lista na performance da operação é muito menor do que se poderia esperar.\u003C\u002Fspan\u003E\u003C\u002Fli\u003E\r\n\u003C\u002Fol\u003E\r\n\u003Cspan style=\"font-weight: 400;\"\u003ENo próximo artigo, a conversa é sobre o uso de listas em arquivos CSV. \u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EAté lá!\u003C\u002Fspan\u003E","excerpt":"\u003Cp\u003EListas, arrays, matrizes, vetores. Independente do nome que você prefira usar, cedo ou tarde vai ter que lidar com estes tipos de estrutura de dados. Estas não são estruturas comuns no mundo relacional, porém temos que ter em mente que hoje a diversidade de formatos e estruturas é uma regra no mundo corporativo. Mais que…\u003C\u002Fp\u003E\n","link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server\u002Fazure-sql-db-trabalhando-com-listas-e-arrays-parte-1","date":"11 jan, 2022","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2022\u002F01\u002F11075531\u002FNews-Blog-Graphic.jpg","externalMention":"","author":{"id":"452","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2018\u002F05\u002F30184745\u002FwagnercriveliniP-128x128.jpeg","name":"Wagner Crivelini","description":"Consultor Sênior na Microsoft, na área de Data Insights para América Latina. Especialista em bancos de dados, é colunista em diversos portais de TI do Brasil e do exterior, com mais de 100 artigos técnicos publicados. É também co-produtor do DatabaseCast, primeiro podcast brasileiro sobre bancos de dados.","slug":"wagner-crivelini","url":"https:\u002F\u002Fimasters.com.br\u002Fperfil\u002Fwagner-crivelini","registered":"2010-12-30 11:28:37","social":{"linkedin":null,"youtube":null,"facebook":"","twitter":"https:\u002F\u002Ftwitter.com\u002Fwcrivelini@gmail.com","instagram":null,"github":null,"url":"http:\u002F\u002Fwww.wcrivelini.com.br","mail":"wcrivelini@gmail.com"},"articles_count":87,"views_count":756900,"certifications":null,"conquests":null,"office":null},"categories":[{"title":"SQL Server","slug":"sql-server","id":7212,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server"}],"tags":[{"title":"AZURE SQL DB","slug":"azure-sql-db","id":8875,"link":"https:\u002F\u002Fimasters.com.br\u002Fazure-sql-db"},{"title":"sql server","slug":"sql-server-2","id":324,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server-2"}],"relateds":[],"seo":[],"type":"post"},{"id":155851,"title":"Tabelas Temporais Particionadas - Criando Auditoria de Dados em Tabelas Grandes","content":"Desde a versão 2016 do SQL Server está disponível o recurso para auditoria automática de dados através das Tabelas Temporais.\r\n\r\nEu mesmo publiquei em 2018 aqui no iMasters \u003Ca href=\"https:\u002F\u002Fimasters.com.br\u002Fdata\u002Fsql-server-auditando-dados-com-tabelas-temporais\"\u003Eum artigo tratando deste recurso\u003C\u002Fa\u003E que, além de útil, é muito fácil de implementar.\r\n\r\nRecentemente precisei implementar este recurso em um cliente. Porém, neste caso, tratava-se de uma tabela com mais de 2 bilhões de registros, o que exigiu alguns cuidados especiais, como descrevo a seguir.\r\n\u003Ch2\u003E\u003Cstrong\u003EComo Lidar com Tabelas Grandes\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nUma solução muito usada para melhorar performance de tabelas com muitos registros é o uso de particionamento. Também tratei deste tema aqui no iMasters, em \u003Ca href=\"https:\u002F\u002Fimasters.com.br\u002Fdata\u002Ftrabalhando-com-tabelas-particionadas\"\u003Eum artigo de 2017\u003C\u002Fa\u003E.\r\n\r\nA ideia é subdividir a tabela em inúmeros “blocos” menores. Na prática, vemos a tabela como um só componente e a tratamos como se fosse uma tabela normal. Mas fisicamente ela está segmentada em N partes, sendo que os dados serão alocados em cada partição segundo o valor de uma coluna que chamamos de chave de particionamento.\r\n\r\nNão é preciso dizer que o bom ou mau desempenho das operações com estas tabelas depende muito da escolha da chave de particionamento.\r\n\r\nÉ comum considerar colunas com datas como candidatas para chave de particionamento. Assim, datas próximas tenderão a ser agrupadas na mesma partição.\r\n\r\nUm efeito desta escolha é que novos dados tenderão a ser escritos na mesma partição. Em função disso, neste caso teremos uma partição “quente” para escrita, enquanto todas as demais só terão acesso de leitura.\r\n\u003Ch2\u003EComo Implementar Auditoria de Dados\u003C\u002Fh2\u003E\r\nApesar de simples, a auditoria oferecida pelas tabelas temporais é bastante eficiente e, além de tudo, ocorre automaticamente.\r\n\r\nAo se criar uma tabela temporal, é automaticamente gerada uma tabela histórica com as mesmas colunas que a original.\r\n\r\nQuando ocorre uma atualização ou exclusão de dados da tabela principal (a tabela temporal), o registro antigo é movido para a tabela secundária (chamada tabela histórica).\r\n\r\nAli veremos que este registro terá uma data de validade inicial: \u003Cstrong\u003ESysStartTime\u003C\u002Fstrong\u003E. Esta data informa quando aquele registro sofreu sua ação, seja ela uma inserção ou alteração. Existe também a data em que aquela versão do registro foi “eliminada”: \u003Cstrong\u003ESysEndTime\u003C\u002Fstrong\u003E, que trata de quando o registro foi alterado ou excluído da tabela\r\ntemporal.\r\n\r\nQuando o registro é inserido, ele é escrito na tabela temporal tendo como \u003Cstrong\u003ESysStartTime\u003C\u002Fstrong\u003E a data em que ocorreu este evento. E, como se poderia prever, a coluna \u003Cstrong\u003ESysEndTime\u003C\u002Fstrong\u003E terá o valor NULO. Porém, nada acontece na tabela histórica, visto que esta é a primeira versão do registro.\r\n\r\nQuando tal registro for alterado ou excluído, a versão antiga é movida para a tabela histórica, informando em \u003Cstrong\u003ESysEndTime\u003C\u002Fstrong\u003E a data em que esta versão foi “eliminada”. E tudo isso é controlado automaticamente pelo mecanismo do SQL Server.\r\n\u003Ch2\u003ETabela Temporal Particionada\u003C\u002Fh2\u003E\r\nQual problema pode acontecer ao se criar uma tabela temporal particionada? Normalmente, se estamos particionando uma tabela por ser muito grande, provavelmente a tabela histórica associada a ela também será muito grande. Consequentemente, é altamente recomendável que a tabela histórica também seja\r\nparticionada.\r\n\r\nPorém, se executarmos o processo normal de criação de uma tabela temporal, será gerada uma tabela histórica sem partições. Não importa que seu script esteja particionando a tabela temporal. A histórica não será convertida automaticamente em tabela particionada.\r\n\r\nSendo assim, é necessária uma pequena adaptação do processo, criando primeiramente a tabela histórica com as partições. E depois se cria a tabela temporal particionada que irá apontar para a tabela histórica que já se criou.\r\nÍndices adicionais que sejam criados para a tabela temporal e\u002Fou tabela histórica devem igualmente ser particionados.\r\n\r\nDesta maneira, seu ambiente estará adequado às necessidades e à escala do seu banco de dados.\r\n\u003Ch2\u003ECriando os Objetos\u003C\u002Fh2\u003E\r\n\u003Cp id=\"E495\" class=\"x-scope qowt-word-para-1\"\u003E\u003Cspan id=\"E496\" class=\"qowt-font10-Arial\"\u003EO que dá mais trabalho na criação dessa solução é a \u003C\u002Fspan\u003E\u003Cspan id=\"E497\" class=\"qowt-font10-Arial\"\u003Esequência\u003C\u002Fspan\u003E\u003Cspan id=\"E498\" class=\"qowt-font10-Arial\"\u003E de tarefas a serem executadas.\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E499\" class=\"x-scope qowt-word-para-1\"\u003E\u003Cspan id=\"E500\" class=\"qowt-font10-Arial\"\u003EEm primeiro lugar, é preciso criar o \u003C\u002Fspan\u003E\u003Cspan id=\"E501\" class=\"qowt-font10-Arial\"\u003Efilegroups\u003C\u002Fspan\u003E\u003Cspan id=\"E502\" class=\"qowt-font10-Arial\"\u003E que serão usados.\u003C\u002Fspan\u003E\u003Cspan id=\"E503\" class=\"qowt-font10-Arial\"\u003E \u003C\u002Fspan\u003E\u003Cspan id=\"E504\" class=\"qowt-font10-Arial\"\u003EQuando se trabalha com o SQL Server nativo, é\u003C\u002Fspan\u003E\u003Cspan id=\"E505\" class=\"qowt-font10-Arial\"\u003E altamente recomendável que se use um \u003C\u002Fspan\u003E\u003Cspan id=\"E506\" class=\"qowt-font10-Arial\"\u003Efilegroup\u003C\u002Fspan\u003E\u003Cspan id=\"E507\" class=\"qowt-font10-Arial\"\u003E para cada partição para garantir melhor gerenciamento do banco de dados.\u003C\u002Fspan\u003E\u003Cspan id=\"E508\" class=\"qowt-font10-Arial\"\u003E (No caso d\u003C\u002Fspan\u003E\u003Cspan id=\"E509\" class=\"qowt-font10-Arial\"\u003Eo\u003C\u002Fspan\u003E\u003Cspan id=\"E510\" class=\"qowt-font10-Arial\"\u003E \u003C\u002Fspan\u003E\u003Cspan id=\"E511\" class=\"qowt-font10-Arial\"\u003EAzure SQL Database\u003C\u002Fspan\u003E\u003Cspan id=\"E512\" class=\"qowt-font10-Arial\"\u003E, que é \u003C\u002Fspan\u003E\u003Cspan id=\"E513\" class=\"qowt-font10-Arial\"\u003Eum serviço PAAS\u003C\u002Fspan\u003E\u003Cspan id=\"E514\" class=\"qowt-font10-Arial\"\u003E, não temos controle sobre \u003C\u002Fspan\u003E\u003Cspan id=\"E515\" class=\"qowt-font10-Arial\"\u003Eos \u003C\u002Fspan\u003E\u003Cspan id=\"E516\" class=\"qowt-font10-Arial\"\u003Edatafiles\u003C\u002Fspan\u003E\u003Cspan id=\"E517\" class=\"qowt-font10-Arial\"\u003E \u003C\u002Fspan\u003E\u003Cspan id=\"E518\" class=\"qowt-font10-Arial\"\u003Eusados, por isso normalmente usamos o \u003C\u002Fspan\u003E\u003Cspan id=\"E519\" class=\"qowt-font10-Arial\"\u003Efilegroup\u003C\u002Fspan\u003E\u003Cspan id=\"E520\" class=\"qowt-font10-Arial\"\u003E padrão, o PRIMARY)\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\r\n\u003Cpre\u003E\u003Ccode class=\"language-sql\"\u003E--Criando filegroups\r\n\r\nUSE MASTER\r\n\r\nGO\r\n\r\n\r\n\r\nALTER DATABASE MeuBD ADD FILEGROUP fg2018 ;\r\n\r\nALTER DATABASE MeuBD ADD FILEGROUP fg2019 ;\r\n\r\nALTER DATABASE MeuBD ADD FILEGROUP fg2020 ;\r\n\r\nALTER DATABASE MeuBD ADD FILEGROUP fg2021 ;\r\n\r\nALTER DATABASE MeuBD ADD FILEGROUP fg2022 ;\r\n\r\nALTER DATABASE MeuBD ADD FILEGROUP fg2023 ;\r\n\r\nGO\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\nNo passo seguinte, criamos os datafiles usados por cada partição.\r\n\r\n \r\n\u003Cpre\u003E\u003Ccode class=\"language-sql\"\u003E-- define 1 or more datafile per partition\r\n\r\nUSE MASTER\r\n\r\nGO\r\n\r\n\r\n\r\nALTER DATABASE meuBD ADD FILE ( NAME = N'part2018_1', \r\n\r\n FILENAME = N'C:\\Data\\meuDB_part2018_1.ndf' , \r\n\r\n SIZE = 100MB , MAXSIZE = 100GB , FILEGROWTH = 100MB \r\n\r\n) TO FILEGROUP [fg2018];\r\n\r\n\r\n\r\nALTER DATABASE meuBD ADD FILE ( NAME = N'part2019_1', \r\n\r\n FILENAME = N'C:\\Data\\meuBD_part2019_1.ndf' , \r\n\r\n SIZE = 100MB , MAXSIZE = 100GB , FILEGROWTH = 100MB \r\n\r\n) TO FILEGROUP [fg2019];\r\n\r\n\r\n\r\nALTER DATABASE meuBD ADD FILE ( NAME = N'part2020_1', \r\n\r\n FILENAME = N'C:\\Data\\meuBD_part2020_1.ndf' , \r\n\r\n SIZE = 100MB , MAXSIZE = 100GB , FILEGROWTH = 100MB \r\n\r\n) TO FILEGROUP [fg2020];\r\n\r\n\r\n\r\nALTER DATABASE meuBD ADD FILE ( NAME = N'part2021_1', \r\n\r\n FILENAME = N'C:\\Data\\meuBD_part2021_1.ndf' , \r\n\r\n SIZE = 100MB , MAXSIZE = 100GB , FILEGROWTH = 100MB \r\n\r\n) TO FILEGROUP [fg2021];\r\n\r\n\r\n\r\nALTER DATABASE meuBD ADD FILE ( NAME = N'part2022_1', \r\n\r\n FILENAME = N'C:\\Data\\meuBD_part2022_1.ndf' , \r\n\r\n SIZE = 100MB , MAXSIZE = 100GB , FILEGROWTH = 100MB \r\n\r\n) TO FILEGROUP [fg2022] ;\r\n\r\n\r\n\r\nALTER DATABASE meuBD ADD FILE ( NAME = N'part2023_1', \r\n\r\n FILENAME = N'C:\\Data\\meuBD_part2023_1.ndf' , \r\n\r\n SIZE = 100MB , MAXSIZE = 100GB , FILEGROWTH = 100MB \r\n\r\n) TO FILEGROUP [fg2023];\r\n\r\nGO\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\n \r\n\r\n\u003Cspan id=\"E926\" class=\"qowt-font10-Arial\"\u003ENo passo 3, se define \u003C\u002Fspan\u003E\u003Cspan id=\"E927\" class=\"qowt-font10-Arial\"\u003Ea função de particionamento.\u003C\u002Fspan\u003E\r\n\u003Cpre\u003E\u003Ccode class=\"language-sql\"\u003E--Funcao de particionamento\r\n\r\nUSE meuBD\r\n\r\nGO\r\n\r\n\r\n\r\nCREATE PARTITION FUNCTION [fnPartitioningByYear](DATETIME) AS RANGE RIGHT FOR VALUES \r\n\r\n\t(\r\n\r\n\t -- tipo de particionamento: “RANGE RIGHT”\r\n\r\n\t --NAO INFORMAR o primeiro intervalo (01\u002Fjan a 31\u002Fdez\u002F2018) \r\n\r\n\t --dados anteriores a 01\u002Fjan\u002F2019 serao gravados naquela particao\r\n\r\n\t '20190101 00:00:00'\r\n\r\n\t, '20200101 00:00:00'\r\n\r\n\t, '20210101 00:00:00'\r\n\r\n\t, '20220101 00:00:00'\r\n\r\n\t, '20230101 00:00:00'\r\n\r\n\t)\r\n\r\nGO\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\n \r\n\r\nAgora é a vez de criar o esquema de particionamento dos dados.\r\n\u003Cpre\u003E\u003Ccode class=\"language-sql\"\u003E-- Esquema de particionamento \r\n\r\nUSE meuBD\r\n\r\nGO\r\n\r\n\r\n\r\nCREATE PARTITION SCHEME [schPartitioningByYear]\r\n\r\nAS PARTITION [fnPartitioningByYear]\r\n\r\nTO ( fg2018, fg2019, fg2020, fg2021, fg2022, fg2023)\r\n\r\nGO\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\n \r\n\r\n\u003Cspan id=\"E1052\" class=\"qowt-font10-Arial\"\u003EFinalmente podemos criar a primeira tabela, que\u003C\u002Fspan\u003E\u003Cspan id=\"E1053\" class=\"qowt-font10-Arial\"\u003E no nosso caso\u003C\u002Fspan\u003E\u003Cspan id=\"E1054\" class=\"qowt-font10-Arial\"\u003E dever ser\u003C\u002Fspan\u003E\u003Cspan id=\"E1055\" class=\"qowt-font10-Arial\"\u003E necessariamente a tabela histórica. Como esta será também uma tabela particionada, é \u003C\u002Fspan\u003E\u003Cspan id=\"E1056\" class=\"qowt-font10-Arial\"\u003Erequerido que a chave de particionamento faça parte de um índice clusterizado ou chave primária.\u003C\u002Fspan\u003E\r\n\u003Cpre\u003E\u003Ccode class=\"language-sql\"\u003E-- Criar tabela historica\r\n\r\nUSE meuBD\r\n\r\nGO\r\n\r\n\r\n\r\nCREATE TABLE test_temporal_HISTORY(\r\n\r\n id bigint NOT NULL,\r\n\r\n initdate datetime NOT NULL,\r\n\r\n SysStartTime datetime2(7) NOT NULL,\r\n\r\n SysEndTime datetime2(7) NOT NULL\r\n\r\n) ON [schPartitioningByYear](initdate)\r\n\r\n\r\n\r\nGO\r\n\r\n\r\n\r\nCREATE CLUSTERED INDEX ix_test_temporal_History \r\n\r\nON test_temporal_HISTORY (id , initdate)\r\n\r\nGO\r\n\r\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\n\u003Cspan id=\"E1142\" class=\"qowt-font10-Arial\"\u003EAgora, finalmente, definimos a tabela temporal, com sua sintaxe especial. Note que estamos apontando para uma tabela que já existe\u003C\u002Fspan\u003E\u003Cspan id=\"E1144\" class=\"qowt-font10-Arial\"\u003E (e que usa o mesmo modelo de colunas e tipos de dados). Além disso, ela também está associada a um\u003C\u002Fspan\u003E\u003Cspan id=\"E1145\" class=\"qowt-font10-Arial\"\u003E esquema de particionamento.\u003C\u002Fspan\u003E\r\n\u003Cpre\u003E\u003Ccode class=\"language-sql\"\u003E-- Criar tabela temporal\r\n\r\nUSE meuBD\r\n\r\nGO\r\n\r\n\r\n\r\nCREATE TABLE dbo.test_temporal(\r\n\r\n id bigint NOT NULL,\r\n\r\n initdate datetime NOT NULL,\r\n\r\n SysStartTime datetime2(7) GENERATED ALWAYS AS ROW START NOT NULL,\r\n\r\n SysEndTime datetime2(7) GENERATED ALWAYS AS ROW END NOT NULL,\r\n\r\nCONSTRAINT PK_test PRIMARY KEY CLUSTERED \r\n\r\n(\r\n\r\n id ASC,\r\n\r\n initdate\r\n\r\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ,\r\n\r\n PERIOD FOR SYSTEM_TIME ([SysStartTime], [SysEndTime])\r\n\r\n) ON [schPartitioningByYear](initdate)\r\n\r\nWITH\r\n\r\n(\r\n\r\nSYSTEM_VERSIONING = ON ( HISTORY_TABLE = dbo.test_temporal_HISTORY )\r\n\r\n)\r\n\r\nGO\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\n\u003Cspan id=\"E1335\" class=\"qowt-font10-Arial\"\u003EFinalmente temos o ambiente pronto para uso. A consulta a seguir verifica \u003C\u002Fspan\u003E\u003Cspan id=\"E1336\" class=\"qowt-font10-Arial\"\u003Equal o tipo de cada tabela e \u003C\u002Fspan\u003E\u003Cspan id=\"E1337\" class=\"qowt-font10-Arial\"\u003Ese \u003C\u002Fspan\u003E\u003Cspan id=\"E1338\" class=\"qowt-font10-Arial\"\u003Eelas são particionadas ou não.\u003C\u002Fspan\u003E\r\n\u003Cpre\u003E\u003Ccode class=\"language-sql\"\u003E--verificacao\r\n\r\nUSE meuBD\r\n\r\nGO\r\n\r\n\r\n\r\nSELECT db_name() + '.' + OBJECT_SCHEMA_NAME(i.object_id) + '.' + OBJECT_NAME(i.object_id) AS TAB\r\n\r\n\t, MIN(temporal_type_desc) AS temporal_type_desc, CASE WHEN MAX(pstat.partition_number) > 1 THEN 'PARTITIONED' ELSE 'REGULAR' END AS Partition_Type, MAX(pstat.partition_number) AS Partition_count \r\n\r\nFROM sys.dm_db_partition_stats pstat\r\n\r\n\tINNER JOIN sys.indexes i ON pstat.object_id = i.object_id AND pstat.index_id = i.index_id\r\n\r\n\tLEFT JOIN sys.partition_schemes ps on ps.data_space_id = i.data_space_id \r\n\r\n\tLEFT JOIN sys.partition_range_values rv on rv.function_id = ps.function_id AND rv.boundary_id = pstat.partition_number\r\n\r\n\tLEFT JOIN sys.tables t on i.object_id = t.object_id \r\n\r\nWHERE OBJECT_SCHEMA_NAME(i.object_id) <> 'sys' \r\n\r\nGROUP BY i.object_id\r\n\r\nHAVING MAX(pstat.partition_number) > 1\r\n\r\nGO\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F12\u002FTABELAa.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-155855\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F12\u002FTABELAa.jpg.jpg\" alt=\"\" width=\"588\" height=\"111\" \u002F\u003E\u003C\u002Fa\u003E\r\n\u003Ch2 id=\"E1618\" class=\"qowt-stl-Heading3 x-scope qowt-word-para-3\"\u003E\u003Cstrong\u003E\u003Cspan id=\"E1619\"\u003ECo\u003C\u002Fspan\u003E\u003Cspan id=\"E1620\"\u003Ementários Finais\u003C\u002Fspan\u003E\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\n\u003Cp id=\"E1621\" class=\"x-scope qowt-word-para-1\"\u003E\u003Cspan id=\"E1622\" class=\"qowt-font10-Arial\"\u003EA implementação de tabelas temporais particionadas, como se pode ver, é simples\u003C\u002Fspan\u003E\u003Cspan id=\"E1623\" class=\"qowt-font10-Arial\"\u003E.\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E1624\" class=\"x-scope qowt-word-para-1\"\u003E\u003Cspan id=\"E1625\" class=\"qowt-font10-Arial\"\u003EA questão principal aqui é se dar conta da necessidade de particionamento da tabela histórica\u003C\u002Fspan\u003E\u003Cspan id=\"E1626\" class=\"qowt-font10-Arial\"\u003E. Se não tomarmos providências esta\u003C\u002Fspan\u003E\u003Cspan id=\"E1627\" class=\"qowt-font10-Arial\"\u003E \u003C\u002Fspan\u003E\u003Cspan id=\"E1628\" class=\"qowt-font10-Arial\"\u003Etabela\u003C\u002Fspan\u003E\u003Cspan id=\"E1629\" class=\"qowt-font10-Arial\"\u003E ser\u003C\u002Fspan\u003E\u003Cspan id=\"E1630\" class=\"qowt-font10-Arial\"\u003Eá\u003C\u002Fspan\u003E\u003Cspan id=\"E1631\" class=\"qowt-font10-Arial\"\u003E criada automaticamente sem partição nenhuma\u003C\u002Fspan\u003E\u003Cspan id=\"E1632\" class=\"qowt-font10-Arial\"\u003E e muito provavelmente o assunto será esquecido.\u003C\u002Fspan\u003E\u003Cspan id=\"E1633\" class=\"qowt-font10-Arial\"\u003E \u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E1634\" class=\"x-scope qowt-word-para-1\"\u003E\u003Cspan id=\"E1635\" class=\"qowt-font10-Arial\"\u003ENeste cenário, o\u003C\u002Fspan\u003E\u003Cspan id=\"E1636\" class=\"qowt-font10-Arial\"\u003E problema só ser\u003C\u002Fspan\u003E\u003Cspan id=\"E1637\" class=\"qowt-font10-Arial\"\u003Eá\u003C\u002Fspan\u003E\u003Cspan id=\"E1638\" class=\"qowt-font10-Arial\"\u003E descoberto quando a solução já estive\u003C\u002Fspan\u003E\u003Cspan id=\"E1639\" class=\"qowt-font10-Arial\"\u003Er\u003C\u002Fspan\u003E\u003Cspan id=\"E1640\" class=\"qowt-font10-Arial\"\u003E em produção\u003C\u002Fspan\u003E\u003Cspan id=\"E1641\" class=\"qowt-font10-Arial\"\u003E e começar a haver problemas de performance para consultas da tabela histórica.\u003C\u002Fspan\u003E\u003Cspan id=\"E1642\" class=\"qowt-font10-Arial\"\u003E \u003C\u002Fspan\u003E\u003Cspan id=\"E1643\" class=\"qowt-font10-Arial\"\u003EE então os esforços necessários para correção serão muito maiores e mais impactantes.\u003C\u002Fspan\u003E\u003C\u002Fp\u003E","excerpt":"\u003Cp\u003EDesde a versão 2016 do SQL Server está disponível o recurso para auditoria automática de dados através das Tabelas Temporais.\u003C\u002Fp\u003E\n","link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server\u002Ftabelas-temporais-particionadas-criando-auditoria-de-dados-em-tabelas-grandes","date":"5 jan, 2021","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F08\u002F24172315\u002F1768.sql_logob.jpg","externalMention":"","author":{"id":"452","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2018\u002F05\u002F30184745\u002FwagnercriveliniP-128x128.jpeg","name":"Wagner Crivelini","description":"Consultor Sênior na Microsoft, na área de Data Insights para América Latina. Especialista em bancos de dados, é colunista em diversos portais de TI do Brasil e do exterior, com mais de 100 artigos técnicos publicados. É também co-produtor do DatabaseCast, primeiro podcast brasileiro sobre bancos de dados.","slug":"wagner-crivelini","url":"https:\u002F\u002Fimasters.com.br\u002Fperfil\u002Fwagner-crivelini","registered":"2010-12-30 11:28:37","social":{"linkedin":null,"youtube":null,"facebook":"","twitter":"https:\u002F\u002Ftwitter.com\u002Fwcrivelini@gmail.com","instagram":null,"github":null,"url":"http:\u002F\u002Fwww.wcrivelini.com.br","mail":"wcrivelini@gmail.com"},"articles_count":87,"views_count":756900,"certifications":null,"conquests":null,"office":null},"categories":[{"title":"SQL Server","slug":"sql-server","id":7212,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server"}],"tags":[{"title":"sql","slug":"sql","id":706,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql"},{"title":"sql server","slug":"sql-server-2","id":324,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server-2"},{"title":"Tabelas temporais","slug":"tabelas-temporais","id":8793,"link":"https:\u002F\u002Fimasters.com.br\u002Ftabelas-temporais"}],"relateds":[],"seo":[],"type":"post"},{"id":155290,"title":"Entendendo os Recursos de Criptografia do AZURE SQL Database","content":"Recentemente precisei apresentar para um cliente um material com noções básicas dos recursos de criptografia disponíveis no AZURE SQL Database.\r\n\r\nSe você já entende os recursos disponíveis no SQL Server 2016 ou superior, aviso que este artigo não vai muito além disso, a não ser talvez pela integração do SQL DATABASE com o KEY VAULT.\r\n\r\nSe esse não é o seu caso, apresento a seguir cada um desses recursos, assim como exemplos de implementação.\r\n\u003Ch2\u003E\u003Cstrong\u003EEncriptação Default dos Serviços Azure\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nTodos os dados gravados em AZURE, seja em qual serviço for, já dispõem de um nível básico de proteção através da Encriptação em Repouso.\r\n\r\nNo caso, estamos falando de discos encriptados. Ela usa chaves simétricas, o que significa que tanto a escrita do dado (encriptação) como a leitura dele (decriptação) são feitas usando a mesma chave.\r\n\r\nEste tipo de encriptação oferece proteção contra ataques físicos ao hardware (isto é: aos datacenters que proveem os serviços de AZURE).\r\n\r\nPara qualquer efeito prático, eu diria que este é o último nível de proteção esperado para os seus dados. Obviamente é muito mais importante para a sua empresa se proteger contra os ataques feitos pela rede. E aí entram os recursos de encriptação para o seu banco de dados.\r\n\u003Ch2\u003E\u003Cstrong\u003EEncriptação ao Nível de Banco de Dados\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nAssim como o SQL Server on-premises, o serviço do AZURE SQL DATABASE usa basicamente 03 tipos de criptografia:\r\n\u003Cul\u003E\r\n \t\u003Cli\u003ECriptografia de Dados Transparente (TDE)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EALWAYS ENCRYPTED\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EMáscara de Dados Dinâmica (DDM)\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E\r\nEstes métodos são completamente diferentes entre si, pois TDE é uma criptografia aplicada à base de dados inteira, ALWAYS ENCRYPTED trabalha com encriptação ao nível de coluna e DDM, finalmente, não é de fato uma encriptação, mas sim um mascaramento lógico dos dados.\r\n\r\nA seguir, apresento mais detalhes de cada método e exemplos de implementação.\r\n\u003Ch2\u003E\u003Cstrong\u003ECriptografia de Dados Transparente (TDE)\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nUma vez que TDE se aplica ao nível de base dados, tudo dentro da base, assim como seus backups, é encriptado.\r\nNaturalmente, os processos de encriptação do dado no momento da escrita e sua decriptação durante a leitura são automáticos e se utilizam de uma chave simétrica que é gerenciada pelo serviço.\r\n\r\nA implementação do TDE no AZURE SQL Database é muito simples e é implementada por default em todas as novas bases de dados que você criar.\r\n\r\nPara mudar esta configuração nas bases antigas ou desativar a encriptação em bases novas (o que não me parece boa ideia), acesse o portal do AZURE, localize a base de dados que deseja configurar, role o menu até encontrar o grupo SECURITY e escolha a guia TRANSPARENT DATA ENCRYPTION, marcando o serviço como ON ou OFF.\r\n\r\n[caption id=\"attachment_155291\" align=\"alignnone\" width=\"2215\"]\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F06\u002FTDE1.jpg\"\u003E\u003Cimg class=\"wp-image-155291 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F06\u002FTDE1.jpg\" alt=\"\" width=\"2215\" height=\"1105\" \u002F\u003E\u003C\u002Fa\u003E Figura 1: Configurando TDE no AZURE SQL DATABASE[\u002Fcaption]\r\n\r\nEntenda que existem duas chaves de encriptação aqui. Uma é a Database Encryption Key (DEK), que efetivamente encripta os dados da base. Com a configuração apresentada acima, significa que ativamos a DEK desta base de dados.\r\n\r\nQuando se usa geo-replicação em bases com TDE, por exemplo, a(s) base(s) secundária(s) compartilha(m) a mesma chave de encriptação da base primária, ou seja, a mesma DEK.\r\n\r\nMas existe um mecanismo de proteção desta chave, que é oferecido por um segundo certificado, que chamamos de Protetor do TDE. O protetor atua ao nível de servidor e, por default, a chave criptográfica deste protetor é gerenciada pelo próprio serviço do AZURE SQL Database. Todo ciclo de vida desta chave (criação, prazo de validade e\r\nexpiração) é gerenciado automaticamente.\r\n\u003Ch2\u003E\u003Cstrong\u003ETDE-BYOK\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nExiste uma outra forma de trabalho, em que o usuário assume o controle do gerenciamento da chave de encriptação do protetor do TDE. Esta alternativa é chamada de BYOK (sigla em inglês para “Bring Your Own Key”).\r\n\r\nPara sua implementação, é preciso respeitar 2 principais requisitos:\r\n1. SQL DATABASE precisa necessariamente estar integrado ao AAD.\r\n2. KEY VAULT precisa necessariamente ter a opção SOFT-DELETE ativada (para evitar problemas com chaves apagadas acidentalmente). Esta opção está disponível no momento da criação do cofre. Caso deseje usar um cofre que foi criado sem esta funcionalidade, você pode configurá-lo usando POWERSHELL. Importante saber que,\r\numa vez ativada, esta mudança é irreversível.\r\n\r\nUma vez resolvidos estes requisitos, basta criar uma chave no KEY VAULT (via portal do AZURE, se preferir) e buscar o servidor SQL no portal do AZURE, já que agora estamos tratando da chave criptográfica do Protetor do TDE.\r\n\r\nNa sequência, procure o grupo SECURITY e escolha a guia TRANSPARENT DATA ENCRYPTION novamente. Você verá uma imagem ligeiramente diferente e ali poderá escolher a opção CUSTOMER-MANAGED KEY, informar o nome do Key Vault a ser usado e apontar para chave que havia criado lá. Ao final, basta salvar a nova\r\nconfiguração.\r\n\r\n[caption id=\"attachment_155294\" align=\"alignnone\" width=\"451\"]\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner01.jpg.jpg\"\u003E\u003Cimg class=\"wp-image-155294 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner01.jpg.jpg\" alt=\"\" width=\"451\" height=\"557\" \u002F\u003E\u003C\u002Fa\u003E Figura 2: Configurando TDE-BYOK[\u002Fcaption]\r\n\r\nEsta operação não envolve downtime e não requer nova encriptação de dados. É apenas a troca da chave usada pelo protetor do TDE.\r\n\u003Ch2\u003E\u003Cstrong\u003EALWAYS ENCRYPTED\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nEsta criptografia trata de encriptação de informações sigilosas, como número de documentos, cartões de crédito etc. Por isso é implementada ao nível de coluna.\r\n\r\nDesse modo, o mecanismo do SQL DB não tem acesso à chave de encriptação. O dado é encriptado na aplicação, enviado como uma coluna binária e então armazenado como tal. Seu significado é desconhecido a menos que se tenha acesso à chave utilizada.\r\n\r\nO resultado aqui é que a coluna só é legível para quem acessar o dado através do driver adequado. Nem mesmo os proprietários do banco terão acesso a esta informação (apenas ao valor encriptado, é claro).\r\n\r\n[caption id=\"attachment_155297\" align=\"alignnone\" width=\"471\"]\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner02.jpg.jpg\"\u003E\u003Cimg class=\"wp-image-155297 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner02.jpg.jpg\" alt=\"\" width=\"471\" height=\"172\" \u002F\u003E\u003C\u002Fa\u003E Figura 3: Implementação de ALWAYS ENCRYPTED[\u002Fcaption]\r\n\r\nÉ possível implementar o ALWAYS ENCRYPTED através de dois métodos diferentes:\r\n\u003Cul\u003E\r\n \t\u003Cli\u003ECom Chave Determinística: de modo que se possa fazer comparações de igualdade (leia-se: permite usar o campo encriptado na cláusula WHERE)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EChave aleatória (“randômica”): encripta dados de maneira aleatória, oferecendo maior segurança. Porém, você não vai conseguir usar este campo para fazer comparações, porque o resultado encriptado não é necessariamente sempre o mesmo. Para mais informações, consulte a documentação citada nas LEITURAS SUGERIDAS.\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E\r\nO processo de encriptação usa duas chaves: a chave mestra e a chave de encriptação da coluna. Uma funcionalidade que não é default apesar de ser de extrema importância é armazenar estas chaves no AZURE KEY VAULT, para garantir a maior proteção possível. O roteiro a seguir mostra todas as etapas do processo.\r\n\r\nPrimeiramente eu criei a tabela desejada, ainda sem encriptação. IMPORTANTE: utilizei o SQL Server Management Studio versão 18.5 (ou SSMS). Versões antigas podem apresentar assistentes e configurações diferentes.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002FWagner03.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-155298\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002FWagner03.jpg.jpg\" alt=\"\" width=\"592\" height=\"75\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nMeu objetivo era proteger os dados da coluna DOCUMENTO, que armazenaria o CPF do usuário. Então o passo seguinte foi procurar a guia SECURITY para o meu banco de dados, cliquei o botão direito e escolhi ALWAYS ENCRYPTED KEYS. A chave mestra foi a primeira a ser criada.\r\n\r\n[caption id=\"attachment_155300\" align=\"alignnone\" width=\"316\"]\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner04.jpg.jpg\"\u003E\u003Cimg class=\"wp-image-155300 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner04.jpg.jpg\" alt=\"\" width=\"316\" height=\"362\" \u002F\u003E\u003C\u002Fa\u003E Figura 4: Definição de chaves do ALWAYS ENCRYPTED[\u002Fcaption]\r\n\r\nO assistente pediu que informasse o nome da chave mestra, onde ela seria armazenada (escolha sempre AZURE KEY VAULT, caso já tenha contratado o serviço). Então informei minha assinatura dos serviços AZURE, o nome do cofre que desejava usar. Finalmente cliquei em GENERATE KEY e então OK.\r\n\r\n[caption id=\"attachment_155301\" align=\"alignnone\" width=\"434\"]\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner05.jpg.jpg\"\u003E\u003Cimg class=\"wp-image-155301 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner05.jpg.jpg\" alt=\"\" width=\"434\" height=\"392\" \u002F\u003E\u003C\u002Fa\u003E Figura 5: Definição da chave mestra (COLUMN MASTER KEY)[\u002Fcaption]\r\n\r\nEm seguida, repeti o processo para criar uma chave de encriptação de coluna. Comecei clicando botão direito sobre o grupo desejado, informei o nome da nova chave e a chave mestra que iria usar (aquela que acabei de criar na etapa anterior).\r\n\r\nNeste ponto, já tinha os elementos para encriptar a coluna desejada. Então localizei a tabela que continha a coluna a ser encriptada, cliquei botão direito outra vez e ativei o assistente ENCRYPT COLUMNS.\r\n\r\n[caption id=\"attachment_155302\" align=\"alignnone\" width=\"360\"]\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner06.jpg.jpg\"\u003E\u003Cimg class=\"wp-image-155302 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner06.jpg.jpg\" alt=\"\" width=\"360\" height=\"336\" \u002F\u003E\u003C\u002Fa\u003E Figura 6: Encriptando colunas desejadas[\u002Fcaption]\r\n\r\nO próximo passo foi escolher a coluna a ser encriptada, tipo de encriptação e qual chave de encriptação de coluna deveria ser usada. E então encerrei o processo com o conhecido NEXT-NEXT-FINISH.\r\n\r\n[caption id=\"attachment_155303\" align=\"alignnone\" width=\"469\"]\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner07.jpg.jpg\"\u003E\u003Cimg class=\"wp-image-155303 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner07.jpg.jpg\" alt=\"\" width=\"469\" height=\"421\" \u002F\u003E\u003C\u002Fa\u003E Figura 7: Especificando a chave e tipo de encriptação da coluna[\u002Fcaption]\r\n\r\nA coluna DOCUMENTO está finalmente encriptada. Mas a tabela continua vazia e são necessários cuidados especiais para inserir dados nesta nova coluna encriptada.\r\n\r\nA primeira ação necessária é alterar os parâmetros de conexão da sua aplicação e ou IDE para trabalhar com ALWAYS ENCRYPTED. Como comentei anteriormente, é necessário usar driver de conexão que suporte este tipo de criptografia.\r\n\r\nPara mostrar como isso funciona, preparei uma simulação diretamente no SSMS. Abri uma nova janela configurando uma nossa sessão: ali mantive o login e senha queestava usando, mas especifiquei o nome do meu banco de dados na aba CONNECTION PROPERTIES e habilitei a opção ENABLE ALWAYS ENCRYPTED na aba ALWAYS ENCRYPTED, como mostra a imagem a seguir.\r\n\r\n[caption id=\"attachment_155304\" align=\"alignnone\" width=\"300\"]\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner8.jpg.jpg\"\u003E\u003Cimg class=\"wp-image-155304 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner8.jpg.jpg\" alt=\"\" width=\"300\" height=\"313\" \u002F\u003E\u003C\u002Fa\u003E Figura 8: Configurando a conexão para suporte ao ALWAYS ENCRYPTED[\u002Fcaption]\r\n\r\nPor que especifiquei o banco de dados na conexão? Simples. O driver de conexão necessita acesso à chave criptográfica da coluna e, evidentemente, esta chave está configurada apenas nesta base de dados.\r\n\r\nResolvido o primeiro ponto, vamos ao segundo. É necessário criar uma consulta parametrizada para que a variável usada seja devidamente encriptada antes da inserção do registro. Com estes cuidados, eu consigo executar comandos DML usando texto plano (encriptação\u002Fdecriptação são providenciadas pela própria conexão).\r\n\r\n[caption id=\"attachment_155305\" align=\"alignnone\" width=\"405\"]\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner9.jpg.jpg\"\u003E\u003Cimg class=\"wp-image-155305 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner9.jpg.jpg\" alt=\"\" width=\"405\" height=\"272\" \u002F\u003E\u003C\u002Fa\u003E Figura 9: Inserindo dados em tabela com coluna ALWAYS ENCRYPTED[\u002Fcaption]\r\n\r\nObserve que escrita e leitura funcionaram normalmente, como se vê na figura acima. Só por conferência, abro agora uma conexão normal para ler os dados... e então apenas dados encriptados são apresentados.\r\n\r\n[caption id=\"attachment_155306\" align=\"alignnone\" width=\"404\"]\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner10.jpg.jpg\"\u003E\u003Cimg class=\"wp-image-155306 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner10.jpg.jpg\" alt=\"\" width=\"404\" height=\"270\" \u002F\u003E\u003C\u002Fa\u003E Figura 10: Visualização da coluna encriptada quando se usa conexão normal[\u002Fcaption]\r\n\r\nCaso deseje dar privilégios para que um usuário ou grupo tenham acesso aos dados encriptados, é preciso especificar estas permissões, como mostra o quadro a seguir.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner11.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-155307\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner11.jpg.jpg\" alt=\"\" width=\"592\" height=\"46\" \u002F\u003E\u003C\u002Fa\u003E\r\n\u003Ch2\u003E\u003Cstrong\u003EMáscara de Dados Dinâmica (DDM)\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nDDM não é propriamente uma encriptação dos dados de uma coluna, mas apenas seu mascaramento enquanto são lidos. Portanto não é um tratamento físico e sim lógico: acrescenta uma determinada máscara aos dados para que eles não sejam inteiramente legíveis.\r\n\r\nA máscara é aplicada para exibição dos dados no momento da consulta. E se aplica a todos usuários, exceto aqueles que tenham privilégio especial sobre a tabela envolvida. Esse acesso é controlado atribuindo ou revogando privilégio de UNMASK. Porém este privilégio é atribuído ao nível de base de dados, isto é, autoriza leitura de TODAS as colunas mascaradas existentes no banco.\r\n\r\nPor ser uma operação lógica, o tipo de máscara usada pode ser alterado a qualquer momento sem nenhum impacto nos dados. Veja a documentação para mais detalhes sobre os tipos de mascaramento disponíveis.\r\n\r\nO código abaixo ilustra a criação de colunas com DDM e atribuição de privilégio de leitura para um usuário comum. IMPORTANTE: como este batch inclui uma inserção de registro com coluna encriptada ALWAYS ON, é necessário estabelecer uma conexão com o SQL Server conforme descrito na seção anterior.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner12.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-155308\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner12.jpg.jpg\" alt=\"\" width=\"591\" height=\"114\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner13.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-155309\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner13.jpg.jpg\" alt=\"\" width=\"589\" height=\"123\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nUsuários com perfil de DBONWER herdam o privilégio de controle sobre a máscara e, portanto, lerão todos os dados. Porém o usuário “PeDeChinelo” vai ler dados mascarados, como mostra a imagem a seguir.\r\n\r\n[caption id=\"attachment_155310\" align=\"alignnone\" width=\"479\"]\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner14.jpg.jpg\"\u003E\u003Cimg class=\"wp-image-155310 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner14.jpg.jpg\" alt=\"\" width=\"479\" height=\"325\" \u002F\u003E\u003C\u002Fa\u003E Figura 11: Usuário sem privilégio especial vendo dados mascarados[\u002Fcaption]\r\n\r\nObserve neste exemplo que criei estas colunas com DDM na mesma tabela que já possuía uma coluna com ALWAYS ENCRYPTED e dentro de uma base que trabalha com TDE.\r\n\r\nEm outras palavras, podemos combinar os diferentes tipos de criptografia dentro do AZURE SQL DATABASE. (A menos, é claro, que se tente criar uma coluna ALWAYS ENCRYPTED e adicionar uma máscara DDM, o que não faz nenhum sentido, visto que o dado já está fisicamente encriptado).\r\n\u003Ch2\u003E\u003Cstrong\u003EComentários Finais\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nSegurança de dados é um tópico de grande importância, especialmente em se tratando de bancos de dados na nuvem.\r\n\r\nComo se pode ver nos exemplos apresentados aqui, a implementação dos vários tipos de proteção de dados no AZURE SQL DATABASE é bastante simples e praticamente idêntica ao que se faz em servidores on-premises.\r\n\r\nJá a integração com AZURE KEY VAULT apresenta um custo insignificante se comparado ao nível de proteção que oferece, seja para serviços da nuvem e\u002Fou on-premises.\r\n\u003Ch2\u003E\u003Cstrong\u003ELeituras Sugeridas\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\n1. \u003Ca href=\"https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fazure\u002Fazure-sql\u002Fdatabase\u002Fsecurity-overview\"\u003EAn overview of Azure SQL Database &amp; SQL Managed Instance security capabilities\u003C\u002Fa\u003E por MICROSOFT.\r\n\r\n2. \u003Ca href=\"https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fazure\u002Fazure-sql\u002Fdatabase\u002Ftransparent-data-encryption-tde-overview?tabs=azure-portal\"\u003ETransparent data encryption for SQL Database, SQL Managed Instance &amp; Azure Synapse\u003C\u002Fa\u003E por MICROSOFT\r\n\r\n3. \u003Ca href=\"https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fsql\u002Frelational-databases\u002Fsecurity\u002Fencryption\u002Falways-encrypted-database-engine?view=sql-server-ver15\"\u003EAlways Encrypted\u003C\u002Fa\u003E por MICROSOFT.\r\n\r\n4. \u003Ca href=\"https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fsql\u002Frelational-databases\u002Fsecurity\u002Fencryption\u002Falways-encrypted-query-columns-ssms?view=sql-server-ver15\"\u003EQuery columns using Always Encrypted with SQL Server Management Studio\u003C\u002Fa\u003E por MICROSOFT\r\n\r\n5. \u003Ca href=\"https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fsql\u002Frelational-databases\u002Fsecurity\u002Fdynamic-data-masking?view=sql-server-ver15\"\u003EDynamic Data Masking\u003C\u002Fa\u003E por MICROSOFT.","excerpt":"\u003Cp\u003ERecentemente precisei apresentar para um cliente um material com noções básicas dos recursos de criptografia disponíveis no AZURE SQL Database.\u003C\u002Fp\u003E\n","link":"https:\u002F\u002Fimasters.com.br\u002Fdata\u002Fentendendo-os-recursos-de-criptografia-do-azure-sql-database","date":"1 jul, 2020","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002F17104843\u002FAZURE.jpg","externalMention":"","author":{"id":"452","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2018\u002F05\u002F30184745\u002FwagnercriveliniP-128x128.jpeg","name":"Wagner Crivelini","description":"Consultor Sênior na Microsoft, na área de Data Insights para América Latina. Especialista em bancos de dados, é colunista em diversos portais de TI do Brasil e do exterior, com mais de 100 artigos técnicos publicados. É também co-produtor do DatabaseCast, primeiro podcast brasileiro sobre bancos de dados.","slug":"wagner-crivelini","url":"https:\u002F\u002Fimasters.com.br\u002Fperfil\u002Fwagner-crivelini","registered":"2010-12-30 11:28:37","social":{"linkedin":null,"youtube":null,"facebook":"","twitter":"https:\u002F\u002Ftwitter.com\u002Fwcrivelini@gmail.com","instagram":null,"github":null,"url":"http:\u002F\u002Fwww.wcrivelini.com.br","mail":"wcrivelini@gmail.com"},"articles_count":87,"views_count":756900,"certifications":null,"conquests":null,"office":null},"categories":[{"title":"Data","slug":"data","id":16,"link":"https:\u002F\u002Fimasters.com.br\u002Fdata"},{"title":"SQL Server","slug":"sql-server","id":7212,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server"}],"tags":[{"title":"azure","slug":"azure","id":2238,"link":"https:\u002F\u002Fimasters.com.br\u002Fazure"},{"title":"Azure SQL Database","slug":"azure-sql-database","id":8420,"link":"https:\u002F\u002Fimasters.com.br\u002Fazure-sql-database"},{"title":"criptografia","slug":"criptografia","id":318,"link":"https:\u002F\u002Fimasters.com.br\u002Fcriptografia"},{"title":"dados","slug":"dados","id":374,"link":"https:\u002F\u002Fimasters.com.br\u002Fdados"},{"title":"database","slug":"database","id":348,"link":"https:\u002F\u002Fimasters.com.br\u002Fdatabase"}],"relateds":[],"seo":[],"type":"post"},{"id":154949,"title":"Bate-bola com Grafos e SQL Server Parte 3 – Visualizando Dados","content":"Desta vez o enfoque é na análise de dados, mais especificamente a visualização dos grafos que foram criados. Eu prefiro começar a conversa com o porquê e depois falo do como. Ou seja, começo mostrando para que serve a visualização dos grafos e, na sequência, apresento como construir um dashboard simples destes grafos.\r\n\u003Ch2\u003E\u003Cstrong\u003EAnalisando Dados em um Dashboard\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nÉ natural que a imagem de milhares de grafos sobrepostos seja muita parecida com uma nuvem. Os poucos “raios” que possam despontar dessa nuvem representam os nós que possuem poucas conexões, geralmente um númeor muito menor que a média dos demais.\r\n\r\nA imagem a seguir apresenta os grafos de cerca de 11 mil jogadores que disputaram partidas de campeonatos europeus entre 2008 e 2015. Considerando este universo (11 mil grafos), fica claro que a quantidade de “raios” que desgarram da nuvem representa um número muito pequeno de nós. E, de fato, fica evidente que são nós que apresentam poucas conexões.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri1.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154950\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri1.jpg.jpg\" alt=\"\" width=\"593\" height=\"325\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nDependendo do que se espera analisar, pode ser vantajoso analisar os grafos fazendo um “zoom” na imagem. Por exemplo, no estudo a seguir, estou observando o universo de jogadores que fizeram parte do elenco do time escocês ABERDEEN durante os 7 anos de histórico. Observo que 93 atletas jogaram pelo time durante este período,\r\nsendo que 01 deles, Andrew Considine, foi o recordista de conexões: 44 no total.\r\n\r\nEm outras palavras, este atleta teve oportunidade de jogar com quase metade dos jogadores que fizeram parte do elenco do time durante estas 07 temporadas. Para destacar este atleta em especial, eu movi este nó para lhe dar maior destaque. Veja o resultado na imagem a seguir.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri2.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154951\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri2.jpg.jpg\" alt=\"\" width=\"598\" height=\"328\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nEm seguida, faço um zoom ainda mais detalhado e avalio os jogadores que estavam no elenco nas temporadas de 2008 e 2015 (primeira e última temporadas do histórico em estudo). Nestes grafos fica óbvio que apenas dois jogadores, Peter Powlet e o próprio Considine fizeram parte do elenco tanto na temporada de 2008 como na de\r\n2015.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri3.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154952\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri3.jpg.jpg\" alt=\"\" width=\"590\" height=\"324\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nVamos agora a outro exemplo: o estudo dos caminhos que conectam dois jogadores. No artigo anterior mostrei uma consulta que identificava o caminho mais curto entre Cristiano Ronaldo e Lionel Messi.\r\n\r\nAqui eu apresento os grafos de um desses caminhos (incluindo Albiol e Villa). Fica claro que existem inúmeros caminhos mais longos que ligam estes quatro atletas, isto é, existem dezenas de jogadores que atuaram com Ronaldo e Albiol, outros tantos que jogaram com Albiol e Villa, e mais outros tantos com Villa e Messi.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri4.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154953\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri4.jpg.jpg\" alt=\"\" width=\"596\" height=\"317\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nObservando mais detalhadamente os grafos, se vê que não houve nenhum jogador além de Albiol que tenha jogado com Ronaldo e Vila, pelo simples fato de que não existem conexões entre Ronaldo e Vila que não passem por Albiol. Pelo mesmo princípio, fica claro que Vila foi o único atleta neste período que jogou com Albiol e Messi.\r\n\r\nCom estes exemplos, espero ter demonstrado a utilidade de se visualizar os grafos. Talvez seja por falta de experiência, mas eu ainda não me sinto confortável fazendo uma análise exploratória dos dados diretamente sobre os grafos. Em geral, testo minhas hipóteses fazendo consultas SQL e uso os grafos para evidenciar o que descobri.\r\n\r\nObviamente os grafos ajudam a entender outras características implícitas nos relacionamentos, mas me parece difícil analisar milhares de grafos em busca de um cenário desejado.\r\n\r\nQuem sabe futuramente, usando ferramentas mais versáteis e rápidas, eu venha a mudar minha opinião. Mas hoje eu uso dashboards de grafos principalmente para demonstrar visualmente descobertas que fiz usando outros recursos.\r\n\u003Ch2\u003E\u003Cstrong\u003EConstruindo um Dashboard\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nAgora apresento em linhas gerais como criar um dashboard de grafos no POWER BI. Primeiramente, é recomendável atualizar a versão do POWER BI DESKTOP instalada na sua máquina. Ao abri-lo, escolho a opção GET DATA na tela de início.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri5.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154954\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri5.jpg.jpg\" alt=\"\" width=\"287\" height=\"170\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nAgora informo qual será a fonte de dados que usarei nestes dashboards. Neste caso, escolho “SQL Server” e clico em CONNECT.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri6.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154955\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri6.jpg.jpg\" alt=\"\" width=\"317\" height=\"358\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nEm seguida, informo o nome da instância SQL e base de dados, marco a opção IMPORT e clico na guia ADVANCED. Minha intenção é definir uma consulta SQL cujos dados serão importados para o dashboard.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri7.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154956\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri7.jpg.jpg\" alt=\"\" width=\"587\" height=\"293\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nA consulta que considerei é apresentada a seguir.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri8.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154957\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri8.jpg.jpg\" alt=\"\" width=\"598\" height=\"142\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nUma vez carregados os dados, começo a tratar da sua visualização. Não existe nenhum objeto nativo no POWER BI que permita uma boa análise de grafos. Sendo assim, decido importar um objeto externo especializado em grafos. Para isso, vou na guia VISUALIZATIONS, clico sobre as reticências e depois em IMPORT FROM APPSOURCE.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri9.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154958\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri9.jpg.jpg\" alt=\"\" width=\"289\" height=\"219\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nNa guia MARKETPLACE, faço uma busca pela palavra-chave “graph”. Existem algumas opções, mas os exemplos que apresento neste artigo foram criados usando o objeto ADVANCED GRAPH VISUAL. Basta escolher o objeto e adicioná-lo no seu dashboard. (Recomendo ao leitor avaliar a licença de cada um dos produtos para entender suas condições de uso).\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri10.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154959\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri10.jpg.jpg\" alt=\"\" width=\"269\" height=\"226\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nFinalmente estou pronto para iniciar a construção do dashboard. Minha intenção é construir um grafo que compare os atletas de N clubes em busca de jogadores que fizeram parte demais de uma equipe. (O POWER BI me permite filtrar centenas deles). Clico no objeto que acabo de instalar e início a etapa de configuração. Veja que abaixo da guia VISUALIZATIONS surge uma série opções de configuração.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri11.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154960\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri11.jpg.jpg\" alt=\"\" width=\"401\" height=\"223\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nPara gerar os grafos desejados, preciso lembrar que pretendo ver TIMES (que aqui será o SOURCE NODES=’TEAM’) e os JOGADORES que fizeram parte do elenco (TARGET NODES=’PLAYER2’). A métrica que desejo visualizar é uma contagem de valores distintos de jogadores, isto é, o número de jogadores que fizeram parte do elenco (VALUE=’COUNT(DISTINCT PLAYER2)’).\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri12.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154961\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri12.jpg.jpg\" alt=\"\" width=\"237\" height=\"291\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nUma questão interessante é que meu modelo de grafos não considera um nó ‘Time’, mas este dado aparece no modelo como um atributo da borda edges.PlayingTogether. Ainda assim, consigo criar uma agregação usando este campo como nó de um grafo.\r\n\r\nÉ comum que os usuários recentes tenham alguma dificuldade de identificar os componentes SOURCE e TARGET NODE na construção dos grafos. Porém, basta lembrar o conceito fundamental dos grafos: dois nós associados através de uma borda.\r\n\r\nNeste caso, o usuário precisa apenas identificar quem é o nó principal da sua análise. Se eu montar grafos com a definição invertida, o perfil da “nuvem” de grafos não mudará muito. Mas ao dar um zoom para visualização de detalhes, eu veria que os destaques, inclusive as métricas, não mostrariam o que eu esperava encontrar.\r\n\r\nAo contrário dos outros objetos de visualização do POWER BI, o ADVANCED GRAPH VISUAL não apresenta tantos recursos de formatação quanto se poderia esperar. Porém ele oferece uma experiência adequada em termos de análise, permitindo inclusive rearranjar os nós na tela.\r\n\r\nSeu ponto fraco, porém, é a performance. A velocidade de atualização dos grafos para uma massa com centenas de milhares de nós pode tornar sua exibição inviável.\r\n\u003Ch2\u003E\u003Cstrong\u003EAnalisando Dados no Novo Dashboard \u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nUma vez concluído meu dashboard, começo as análises escolhendo N times do meu interesse. Neste estudo, selecionei quatro times como filtros:\r\n Real Madrid\r\n Barcelona\r\n Bayern\r\n Paris Saint-Germain\r\n\u003Ch2\u003E\u003Cstrong\u003EAnálise 1\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri13.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154962\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri13.jpg.jpg\" alt=\"\" width=\"587\" height=\"326\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nAs primeiras informações que me saltam aos olhos são as seguintes:\r\n1. Apesar de muitos jogadores terem passado pelos quatro times durante as temporadas de 2008 a 2015 (variando entre 57 e 67 jogadores diferentes), existem muito poucas conexões entre os grafos. Em outras palavras, poucos\r\njogadores atuaram por mais que um destes times durante este período.\r\n\r\n2. Nenhum jogador atuou por mais que 2 dos times, visto que não se vê nenhuma conexão entre 3 ou mais grafos.\r\n\r\n3. Nenhum jogador teve oportunidade durante sua carreira de atuar por Real Madrid e Barcelona, nem por Bayern e PSG. (Pelo menos não entre as temporadas de 2008 a 2015).\r\n\r\n4. Houve 04 atletas que jogaram por Bayern e Real neste período\r\n\r\n5. Houve 02 atletas que jogaram por Bayern e Barcelona e outros 02 que jogaram por PSG e Barcelona.\r\n\r\n6. Houve apenas 01 atleta que jogou pelo Real e PSG. Dando um zoom na imagem, identifico que este atleta foi Angel Di Maria, o argentino.\r\n\u003Ch2\u003E\u003Cstrong\u003EAnálise 2\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nFazendo um novo filtro por temporada (SEASON), observo que houve um único caso de jogador que atuaou por 2 times diferentes na temporada de 2011. Foi Maxwell (brasileiro), que atuou pelo PSG e pelo Barcelona.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri14.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154963\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri14.jpg.jpg\" alt=\"\" width=\"584\" height=\"323\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nO leitor mais atento perceberá que o número de jogadores de cada time mudou nesta nova análise. Isso ocorre simplesmente porque agora vemos o número de jogadores atuantes na temporada 2011\u002F2012, acompanhando o filtro que foi aplicado.\r\n\u003Ch2\u003E\u003Cstrong\u003EComentários Finais\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nComo se pode ver, uma simples imagem pode oferecer um sem-número de informações. Na minha opinião, este é o ponto alto dos Grafos.\r\n\r\nÉ evidente que um dashboard precisa de um tratamento estético mais elaborado, porém minha intenção neste artigo era apenas mostrar como evidenciar características importantes dos relacionamentos de dados usando grafos.\r\n\r\nMesmo considerando a limitação da velocidade de atualização dos dados, este tipo de dashboard pode ser muito útil para pequenas massas de dados (na ordem de milhares de grafos).\r\n\u003Ch2\u003E\u003Cstrong\u003ELeituras Sugeridas\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\n1. SQL Graph Architecture por MICROSOFT.\r\n2. Graph processing with SQL Server and Azure SQL Database por\r\nMICROSOFT.\r\n3. European Soccer Database por Hugo Mathien @KAGGLE\r\n4. Graph Databases for Beginners por Roberto Zicari (série de 5 artigos).","excerpt":"\u003Cp\u003EDesta vez o enfoque é na análise de dados, mais especificamente a visualização dos grafos que foram criados. Eu prefiro começar a conversa com o porquê e depois falo do como. Ou seja, começo mostrando para que serve a visualização dos grafos e, na sequência, apresento como construir um dashboard simples destes grafos. Analisando Dados…\u003C\u002Fp\u003E\n","link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server\u002Fbate-bola-com-grafos-e-sql-server-parte-3-visualizando-dados","date":"13 abr, 2020","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F08\u002F24172315\u002F1768.sql_logob.jpg","externalMention":"","author":{"id":"452","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2018\u002F05\u002F30184745\u002FwagnercriveliniP-128x128.jpeg","name":"Wagner Crivelini","description":"Consultor Sênior na Microsoft, na área de Data Insights para América Latina. Especialista em bancos de dados, é colunista em diversos portais de TI do Brasil e do exterior, com mais de 100 artigos técnicos publicados. É também co-produtor do DatabaseCast, primeiro podcast brasileiro sobre bancos de dados.","slug":"wagner-crivelini","url":"https:\u002F\u002Fimasters.com.br\u002Fperfil\u002Fwagner-crivelini","registered":"2010-12-30 11:28:37","social":{"linkedin":null,"youtube":null,"facebook":"","twitter":"https:\u002F\u002Ftwitter.com\u002Fwcrivelini@gmail.com","instagram":null,"github":null,"url":"http:\u002F\u002Fwww.wcrivelini.com.br","mail":"wcrivelini@gmail.com"},"articles_count":87,"views_count":756900,"certifications":null,"conquests":null,"office":null},"categories":[{"title":"SQL Server","slug":"sql-server","id":7212,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server"}],"tags":[],"relateds":[],"seo":[],"type":"post"},{"id":154930,"title":"Bate-bola com Grafos e SQL Server Parte 2 – Implementando o Modelo","content":"Neste artigo dou sequência no estudo de grafos usando a base de dados European Soccer Database, publicada por Hugo Mathien no KAGGLE.\r\n\r\nDesta vez vou tratar da implementação do modelo de grafos definido no artigo anterior usando o SQL Server 2019.\r\nApresento também algumas consultas e análises sobre estes grafos.\r\n\u003Ch2\u003E\u003Cstrong\u003ECriando as Tabelas\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nDefinido o modelo de grafos, é preciso criar as tabelas e carregar os dados. Para facilitar, apresento abaixo o diagrama do modelo.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini1.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154931\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini1.jpg.jpg\" alt=\"\" width=\"536\" height=\"323\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nA criação das tabelas usando T-SQL não tem segredo: é preciso apenas informar que tipo de tabela está sendo criada, se é nó (“as node”) ou borda (“as edge”). No diagrama acima, os campos que são exibidos com um cifrão (“$”) na frente do nome são criados automaticamente pelo SQL Server. É necessário apenas definir os demais\r\ncampos.\r\n\r\nPara facilitar a identificação das tabelas, criei os esquemas “nodes” e “edges”. O quadro a seguir mostra a sintaxe destas instruções.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini2.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154932\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini2.jpg.jpg\" alt=\"\" width=\"596\" height=\"256\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nApesar da criação de tabelas ser bastante simples, a carga de dados requer mais cuidado, como descrevo a seguir.\r\n\u003Ch2\u003E\u003Cstrong\u003EConsiderações sobre a Carga de Dados\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nEm primeiro lugar, é preciso respeitar a sequência: tabelas de nós são carregadas primeiro. Além dos campos que são definidos explicitamente, as tabelas de nós têm um campo que é criado e gerenciado automaticamente, cujo nome é “$node_id” (seguido de uma sequência de caracteres alfanuméricos que tornam este nome único). Estes campos contém um JSON que identifica o registro, como se vê a seguir.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini3.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154933\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini3.jpg.jpg\" alt=\"\" width=\"386\" height=\"49\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nO passo seguinte é a carga dos dados para tabelas de borda. Na prática, estas tabelas sempre vinculam dois nós, sejam eles quais forem. Do mesmo modo que as tabelas de nós, elas também têm campos que são criados e gerenciados automaticamente.\r\n\r\nOs principais deles são os campos “$from_id” e “$to_id”. Neles são carregados os JSONs que se tem no campo “$node_id” das tabelas de nós vinculadas a esta borda. Perceba que, se a definição da borda tem um “DEPARA”,\r\nsignifica que o relacionamento tem uma direção que é definida na carga dos dados! O quadro a seguir mostra um registro da tabela de borda “edges.PlayersInvolved”.\r\n\r\nEscolhi que a coluna “$from_id” traria informação sobre a partida (match) e a coluna “$to_id” informaria o jogador (player) que participou dela.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini4.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154934\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini4.jpg.jpg\" alt=\"\" width=\"600\" height=\"59\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nEsta escolha precisa ser considerada em todas as consultas que forem feitas sobre estes dados. Se acidentalmente eu inverter a relação, buscando dados com base numa relação jogador\u002Fpartida (ao invés de partida\u002Fjogador), nenhum registro será retornado.\r\n\u003Ch2\u003E\u003Cstrong\u003ECarregando Dados\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nPara que fique mais claro, apresento a seguir o modelo relacional dos dados, com as tabelas e campos que vamos carregar.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini5.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154935\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini5.jpg.jpg\" alt=\"\" width=\"599\" height=\"242\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nA carga de dados para tabelas de nós é elementar, porque geralmente temos uma tabela relacional para a mesma entidade que será representada como nó (neste caso, temos MATCH, TEAM e PLAYER).\r\n\r\nNo caso das bordas, vão existir necessariamente uma ou mais junções de tabelas. Isso porque será preciso trazer dados das tabelas relacionais (os atributos da borda) e dados de grafos, visto que os arquivos JSON das duas tabelas de nós envolvidas na relação serão carregados para as colunas “$from_id” e “$to_id” da tabela de borda.\r\n\r\nPara carga dos dados da borda “edges.TeamsInvolved”, por exemplo, foi necessário criar duas declarações separadas em virtude da modelagem da tabela relacional “dbo.Match”. A primeira declaração busca dados do time local (“home”) e a segunda do time visitante (“away”).\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini6.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154936\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini6.jpg.jpg\" alt=\"\" width=\"598\" height=\"196\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nA carga da tabela de borda “edges.PlayersInvolved” é mais elaborada, já que a tabela relacional “dbo.Match” usa 22 colunas para identificar os jogadores que iniciaram a partida. Deste modo, foram criadas 22 declarações SQL para carregar estes dados.\r\n\r\nNo caso da terceira borda, “edges.PlayingTogether”, a situação é ainda mais complexa. Basicamente, preciso criar para cada jogador uma lista com o nome de todos os jogadores que jogaram no mesmo time que ele. Esta lista não pode ter repetições e não pode associar um jogador a ele mesmo. Existem diversas maneiras de se escrever estas declarações. Eu preferi criar um SQL dinâmico para simplificar a tarefa.\r\n\u003Ch2\u003E\u003Cstrong\u003EAnalisando Dados com T-SQL\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nA principal diferença das declarações SQL que usam grafos é que elas não utilizam o operador JOIN entre as tabelas de nós e bordas. Na verdade, a conexão entre tabelas é feita através do operador MATCH.\r\n\r\nO MATCH é incluído na cláusula WHERE junto com os demais predicados que sejam necessários. Ele define o relacionamento entre nós e bordas, sejam eles quantos forem necessários. A sequência dos nós pode ser colocada da maneira que preferir, desde que mude também os marcadores. Por exemplo (os parênteses, traços e símbolos fazem para da sintaxe):\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini7.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154937\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini7.jpg.jpg\" alt=\"\" width=\"598\" height=\"40\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nComeço apresentando um exemplo simples, que por sinal seria resolvido com igual facilidade no modelo relacional. Desejo saber quantas partidas o Cristiano Ronaldo jogou pela liga espanhola na temporada “2009\u002F2010”.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini8.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154938\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini8.jpg.jpg\" alt=\"\" width=\"596\" height=\"142\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nAgora quero saber quantos jogos Cristiano Ronaldo e Lionel Messi fizeram um contra o outro na Liga Espanhola durante todas as temporadas disponíveis na base (2008 a 2015). Esta é uma informação mais complicada de se extrair no modelo relacional.\r\n\r\nCom grafos, basta especificar uma relação entre o jogador1 e uma partida e verificar se o jogador2 participou da mesma partida. Como sei que Messi e Cristiano nunca jogaram no mesmo time, não me preocupei em identificar os times deles como local ou visitante.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini9.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154939\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini9.jpg.jpg\" alt=\"\" width=\"596\" height=\"161\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nA próxima consulta é bastante difícil de se escrever num modelo relacional. Quero saber com quantos jogadores diferentes Cristiano e Messi jogaram durante este período de 2008 a 2015, não importa se jogaram juntos ou contra eles. No modelo de grafos, a complexidade é a mesma da consulta anterior.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini10.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154940\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini10.jpg.jpg\" alt=\"\" width=\"599\" height=\"168\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nAgora quero identificar quem foi o jogador que mais ganhou jogos em campeonatos nacionais no período estudado e por quantos times diferentes. Este tipo de consulta poderia envolver 03 nós e 02 bordas caso meu modelo não incluísse dois atributos na borda que identifica os jogadores que participaram de uma partida: um informando o\r\nnome do time em que o jogador estava e outro informando se este time era local ou visitante. Deste modo temos uma consulta mais simples e com performance melhor, graças ao alinhamento entre a modelagem da base e as expectativas de uso.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini11.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154941\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini11.jpg.jpg\" alt=\"\" width=\"603\" height=\"175\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nMais um exemplo: quero saber se algum jogador já jogou junto com os goleiros Gianluigi Buffon (ex-seleção italiana) e Julio Cesar (ex-seleção brasileira) em ligas nacionais durante o período em estudo, quais foram os times, ligas e temporadas.\r\n\r\nNeste caso, preciso identificar que esse(s) jogador(es) estavam naquelas partidas no mesmo time que um dos dois goleiros. Aqui é preciso distinguir 3 nós, P1 (Buffon), P2 (o jogador que estou procurando) e P3 (Julio). O time em que P2 jogou a partida precisa ser necessariamente igual ao time onde jogaram Buffon ou ao time do Julio\r\nCesar. A lógica aqui é um pouco mais complexa, pois preciso relacionar P1 e P2 a uma partida M1 e P3 e P2 a outra partida M2. Ainda assim, esta declaração é muito mais simples e rápida do que seria num modelo relacional (mesmo considerando que não criei índices customizados para estas tabelas).\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini12a.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154942\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini12a.jpg.jpg\" alt=\"\" width=\"598\" height=\"86\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini12b.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154943\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini12b.jpg.jpg\" alt=\"\" width=\"595\" height=\"298\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nEste caso era razoavelmente simples, porque de fato existiam 02 jogadores que jogaram diretamente com Buffon e também com Julio Cesar. Dizemos que estes grafos têm 02 graus de separação: Buffon  “Jogador P2” Julio Cesar. Mas o que faríamos se não soubéssemos a “distância” entre estes dois jogadores?\r\n\r\nAqui entra um novo operador de grafos, implementado no SQL Server 2019 (ou superior): SHORTEST_PATH. Este operador informa o menor grau de separação existente entre 02 nós quaisquer. A sintaxe usada define uma chamada recursiva sobre os nós e a borda envolvidos, por essa razão que se usa a cláusula FOR PATH para identificar as tabelas recursivas.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini13.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154944\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini13.jpg.jpg\" alt=\"\" width=\"595\" height=\"90\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nTenha em mente que o objetivo do operador SHORTEST_PATH é encontrar apenas um exemplo de caminho mais curto entre os nós “nó1” e “nó2”. Caso eu queira identificar todos os registros (ou “triplas”) que tenham este mesmo grau de separação, vou precisar escrever outra consulta diferente.\r\n\r\nMeu objetivo no próximo exemplo é descobrir qual o caminho mais curto de jogadores que jogaram com Cristiano Ronaldo e Leonel Messi. O fato de ambos terem jogad o por poucos clubes (2 para Ronaldo e apenas para Messi), aliado à conhecida rixa existente entre Real Madrid e Barcelona, tornam muita baixa probabilidade de encontrar jogadores diretamente ligados a eles dois. Neste exemplo eu uso a borda JOGANDO JUNTOS (“edges.PlayingTogether”), que foi criada exatamente com a finalidade de avaliar as relações entre jogadores que jogaram juntos (pelo mesmo time). Com ela, a sintaxe da consulta será ainda mais simples. O fator principal a se considerar nesta consulta é que não se sabe quantos graus de separação existem entre Messi e Ronaldo, considerando apenas campeonatos nacionais europeus. Por esta razão, tenho que utilizar o operador SHORTEST_PATH.\r\n\r\nMuitas vezes se usa as funções STRING_AGG, LAST_VALUE e\u002Fou COUNT juntamente com o operador SHORT_PATH, visto que elas trazem informações relevantes sobre o caminho e os graus de separação dos grafos. É o que faço na consulta a seguir.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini14.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154945\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini14.jpg.jpg\" alt=\"\" width=\"595\" height=\"278\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nNote que esta consulta retorna um único exemplo de tripla que tenha o mínimo de níveis possíveis para ligar Ronaldo e Messi. Na verdade, a quantidade de triplas que atendem a este quesito é maior. Sabendo que preciso fazer a consulta com 03 graus de separação, fica fácil escrevê-la.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini15.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154946\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini15.jpg.jpg\" alt=\"\" width=\"597\" height=\"327\" \u002F\u003E\u003C\u002Fa\u003E\r\n\u003Ch2\u003E\u003Cstrong\u003EComentários Finais\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nComo se vê, a implementação de tabelas de grafos usando T-SQL é simples e direta. Até mesmo as consultas usando os operadores MATCH e SHORTEST_PATH são relativamente simples de definir e implementar.\r\nDeixo para os leitores mais céticos a tarefa de implementar consultas equivalentes numa base relacional, pois certamente serão consultas muito maiores e mais lentas.\r\n\r\nÉ verdade que o modelo relacional da base original de Hugo Mathien não favorece estas consultas, mas o resultado final, em termos de complexidade e performance, não seria muito diferente mesmo que as tabelas relacionais fossem modeladas com um grau maior de normalização.\r\n\r\nNo terceiro e último artigo desta série, apresentarei a construção de um dashboard para análise dos grafos aqui criados.\r\n\u003Ch2\u003E\u003Cstrong\u003ELeituras Sugeridas\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\n1. SQL Graph Architecture por MICROSOFT.\r\n2. Graph processing with SQL Server and Azure SQL Database por\r\nMICROSOFT.\r\n3. European Soccer Database por Hugo Mathien @KAGGLE\r\n4. Graph Databases for Beginners por Roberto Zicari (série de 5 artigos).\r\n5. SHORTEST_PATH (Transact-SQL) por MICROSOFT.\r\n\r\n \r\n\r\n ","excerpt":"\u003Cp\u003ENeste artigo dou sequência no estudo de grafos usando a base de dados European Soccer Database, publicada por Hugo Mathien no KAGGLE. Desta vez vou tratar da implementação do modelo de grafos definido no artigo anterior usando o SQL Server 2019. Apresento também algumas consultas e análises sobre estes grafos. Criando as Tabelas Definido o…\u003C\u002Fp\u003E\n","link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server\u002Fbate-bola-com-grafos-e-sql-server-parte-2-implementando-o-modelo","date":"30 mar, 2020","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F08\u002F24172315\u002F1768.sql_logob.jpg","externalMention":"","author":{"id":"452","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2018\u002F05\u002F30184745\u002FwagnercriveliniP-128x128.jpeg","name":"Wagner Crivelini","description":"Consultor Sênior na Microsoft, na área de Data Insights para América Latina. Especialista em bancos de dados, é colunista em diversos portais de TI do Brasil e do exterior, com mais de 100 artigos técnicos publicados. É também co-produtor do DatabaseCast, primeiro podcast brasileiro sobre bancos de dados.","slug":"wagner-crivelini","url":"https:\u002F\u002Fimasters.com.br\u002Fperfil\u002Fwagner-crivelini","registered":"2010-12-30 11:28:37","social":{"linkedin":null,"youtube":null,"facebook":"","twitter":"https:\u002F\u002Ftwitter.com\u002Fwcrivelini@gmail.com","instagram":null,"github":null,"url":"http:\u002F\u002Fwww.wcrivelini.com.br","mail":"wcrivelini@gmail.com"},"articles_count":87,"views_count":756900,"certifications":null,"conquests":null,"office":null},"categories":[{"title":"SQL Server","slug":"sql-server","id":7212,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server"}],"tags":[{"title":"Grafos","slug":"grafos","id":3757,"link":"https:\u002F\u002Fimasters.com.br\u002Fgrafos"},{"title":"sql server","slug":"sql-server-2","id":324,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server-2"}],"relateds":[],"seo":[],"type":"post"},{"id":154854,"title":"Bate-bola com Grafos e SQL Server Parte 1 – Definindo o Modelo","content":"É espantosa a popularização que as novas tecnologias de dados alcançaram na última década. Uma das mais bacanas é a utilização de Grafos para análise de dados, apesar de ela não ser propriamente uma tecnologia nova.\r\n\r\nTeoria dos Grafos é um ramo da matemática inventado por Leonhard Euler há quase 300 anos! Seu foco é a análise de relações (complexas) entre entidades.\r\n\r\nVocê pode dizer que um banco relacional também trata de objetos relacionados, mas nele sempre haverá um número pequeno de relações diretas entre um objeto e seus pares.\r\n\r\nNão é comum encontrar um modelo relacional em que uma tabela se relacione diretamente com mais que 10 outras tabelas. Mas quando pensamos, por exemplo, nos relacionamentos entre pessoas numa rede social, os números rapidamente passam dos milhares.\r\n\r\nPortanto, mesmo que dados relacionais e grafos trabalhem com os mesmos princípios (entidades e relacionamentos), eles claramente ocupam nichos distintos. O primeiro trata de relações simples, enquanto os grafos são úteis nos casos em que se trabalha com relações complexas entre entidades.\r\n\r\nExiste inclusive um jogo chamado “Seis Graus de Separação” que alega que você pode rastrear uma rede de relacionamentos de você até qualquer pessoa do planeta envolvendo, no máximo, outras seis pessoas.\r\n\r\nEm outras palavras, seis relacionamentos. A primeira vez que ouvi falar disso foi nos anos 90, numa matéria da\r\nrevista \u003Ca href=\"https:\u002F\u002Fwww.discovermagazine.com\u002Fmagazine\"\u003EDISCOVER MAGAZINE\u003C\u002Fa\u003E. É uma pena que não consegui encontrá-lo no site da revista\r\n\r\nNesta série, mostro como implementar Grafos usando T-SQL, ou seja, apresento códigos, conceitos e funcionalidades para criação de grafos nos seguintes SGBDs:\r\n\u003Cul\u003E\r\n \t\u003Cli\u003EMICROSOFT SQL Server 2017 ou superior (on-premises)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EMICROSOFT PARALLEL DATA WAREHOUSE (on-premises)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EAZURE SQL DATABASE (nuvem)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EAZURE SYNAPSE ANALYTICS (nuvem)\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E\r\nPara fins de exemplo, escolhi uma massa de dados disponível no KAGGLE que trata de resultados de jogos de ligas europeias de futebol entre as temporadas de 2008 e 2015, a \u003Ca href=\"https:\u002F\u002Fwww.kaggle.com\u002Fhugomathien\u002Fsoccer\"\u003EEuropean Soccer Database\u003C\u002Fa\u003E, compartilhada por \u003Ca href=\"https:\u002F\u002Fwww.kaggle.com\u002Fhugomathien\"\u003EHugo Mathien\u003C\u002Fa\u003E.\r\n\u003Ch2\u003E\u003Cstrong\u003EEntendendo o Modelo\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nO diagrama a seguir apresenta um grafo, envolvendo 02 tipos de entidade, diferenciadas por cores, com 03 elementos diferentes em cada uma. Apresenta também 06 tipos de relacionamentos, que são identificados por rótulos.\r\n\r\nPerceba que a entidade “PEDRO”, por exemplo, se relaciona com todos os outros nós através de diferentes relações, com exceção da relação “VIZINHA DE”, que se refere exclusivamente a cidades.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F02\u002FJoão.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154855\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F02\u002FJoão.jpg.jpg\" alt=\"\" width=\"538\" height=\"411\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nQuando trabalhamos com grafos, o foco passa a ser nos elementos de cada entidade, os chamados nós (do inglês “nodes”). Estes nós podem ou não ter atributos associados a eles, dependendo da sua necessidade.\r\n\r\nOutro elemento essencial são as bordas (do inglês “edge”), que definem os relacionamentos que existem entre estes\r\nnós. Observe ainda que as relações têm direção: uma relação é definida de “A” para “B”. Isso será muito importante na hora de definir o modelo e de executar as consultas.\r\n\r\nPara implementar grafos com T-SQL, são necessárias pequenas adaptações nos modelos físico e lógico da base de dados. Assim criamos N tabelas de entidades, contendo todos os nós e atributos referentes a cada entidade. Em seguida criamos M tabelas de bordas, que definem os tipos de relacionamento analisados, informando\r\nque nós estão envolvidos nesta relação.\r\n\r\nEsta estrutura permite armazenar os dados fisicamente de forma muito parecida com os dados relacionais. Ao mesmo tempo, ela nos dá a flexibilidade de analisá-los da maneira desejada, já que o modelo lógico os representa como verdadeiros grafos.\r\n\r\nDetalhe importante: os especialistas alertam que a definição do modelo do grafo está intimamente ligada ao tipo de consultas que se deseja fazer. Em outras palavras, a escolha das bordas, nós e atributos de um modelo pode ser diferente conforme o tipo de consultas que serão feitas sobre estes grafos.\r\n\u003Ch2\u003E\u003Cstrong\u003EExemplo de Modelagem\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nIsto posto, vamos criar nosso modelo de grafos. Meu objetivo é analisar as interações entre jogadores, times e resultados das partidas disputadas em diversas ligas europeias durante o período estudado. O modelo relacional desta base é apresentado a seguir.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F02\u002Fdados.png.png\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154856\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F02\u002Fdados.png.png\" alt=\"\" width=\"530\" height=\"225\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nOBSERVAÇÃO: a massa de dados original foi compartilhada no KAGGLE como uma base do SQLITE. No entanto, a movimentação destas tabelas para o SQL Server 2019 é um processo tradicional que pode ser feito de inúmeras formas, inclusive como movimentação de arquivos CSV. Sendo assim, não me importei em detalhar as\r\noperações desta etapa.\r\n\r\nUma vez disponíveis os dados relacionais, é necessário definir como serão os grafos utilizados. Para isso, preciso definir quais tabelas de nós e de bordas serão criadas e quais os atributos de cada uma delas.\r\n\r\nA intenção do meu modelo é analisar as interações entre jogadores, times e partidas ocorridas. Para ser mais explícito: pretendo analisar interações entre jogadores (quem jogou no mesmo time, quem foi adversário), entre jogadores e times, entre jogadores e as partidas ocorridas (se ele jogou ou não), entre os times que jogaram entre si e entre times e as partidas que jogaram.\r\n\r\nÀ primeira vista, é um modelo bem simples. Porém as relações entre estas entidades crescem muito rapidamente e este é o problema que os grafos procuram resolver. Veja só algumas contas: num torneio com 20 equipes que jogam 38 rodadas envolvendo 22 jogadores.\r\n\r\nA base em estudo contém dados de 11 ligas por 8 temporadas. Teoricamente, isso representaria cerca de 1,5 milhão de combinações. Porém os times mudam de escalação de jogo para jogo, cada equipe seleciona seus 11 titulares dentro um grupo que tem em média 35 jogadores, o que torna mais difícil estimar o número real de combinações.\r\n\r\nConsiderando os tipos de análise que quero executar, defini o modelo com 03 nós e 03 bordas, a saber:\r\n\u003Cul\u003E\r\n \t\u003Cli\u003ENó TIME (team): equipe que participa do torneio\u003C\u002Fli\u003E\r\n \t\u003Cli\u003ENó JOGADOR (player): associado ao time\u003C\u002Fli\u003E\r\n \t\u003Cli\u003ENó PARTIDA (match): traz dados dos confrontos dentro do torneio\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EBorda TIMES ENVOLVIDOS (TeamsInvolved): identifica relação entre as partidas e as equipes participantes\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EBorda JOGADORES ENVOLVIDOS (PlayersInvolved): identifica jogadores que participaram de cada partida.\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EBorda JOGANDO JUNTOS (PlayingTogether): identifica diretamente os jogadores que entraram em campo por uma mesma equipe.\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E\r\nInformações relevantes que serão usadas apenas como filtros foram incluídas no modelo como atributos. Por exemplo: dia do aniversário, altura e peso do jogador foram incluídos como atributos no nó JOGADORES (players), porque se espera que eles não mudem de uma partida para outra.\r\n\r\nEm contrapartida, o time pelo qual ele jogou, se era do time local ou visitante e qual o número da camisa do jogador foram incluídos na borda JOGADORES ENVOLVIDOS (PlayersInvolved), porque são atributos do jogador que podem variar de uma partida para a outra. Ao final, cheguei no seguinte modelo:\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F02\u002Fdados2.png.png\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154857\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F02\u002Fdados2.png.png\" alt=\"\" width=\"465\" height=\"281\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nDevido à natureza das pesquisas que pretendo fazer usando a borda JOGANDO JUNTOS (PlayingTogether), precisei definir o relacionamento como se ele fosse bidirecional. Na prática, não existe este conceito no T-SQL e, portanto, o que pretendo fazer de fato é carregar dados considerando as duas direções (de “A” para “B” e de “B” para “A”). Este é um tópico que tratarei no próximo artigo.\r\n\u003Ch2\u003E\u003Cstrong\u003EComentários Finais\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nNeste primeiro artigo da série, apresentei a definição de um modelo de grafos para analisar partidas de futebol. No próximo artigo, apresentarei a implementação deste modelo no SQL Server 2019 e como funcionam as consultas sobre estes dados.\r\n\u003Ch2\u003E\u003Cstrong\u003ELeituras Sugeridas\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\n1. \u003Ca href=\"https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fsql\u002Frelational-databases\u002Fgraphs\u002Fsql-graph-architecture?view=sql-server-ver15\"\u003ESQL Graph Architecture\u003C\u002Fa\u003E por MICROSOFT.\r\n2. \u003Ca href=\"https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fsql\u002Frelational-databases\u002Fgraphs\u002Fsql-graph-overview?view=sql-server-2017\"\u003EGraph processing with SQL Server and Azure SQL Database\u003C\u002Fa\u003E por\r\nMICROSOFT.\r\n3.\u003Ca href=\"https:\u002F\u002Fwww.kaggle.com\u002Fhugomathien\u002Fsoccer\"\u003E European Soccer Database\u003C\u002Fa\u003E por Hugo Mathien @KAGGLE\r\n4. \u003Ca href=\"http:\u002F\u002Fwww.odbms.org\u002F2015\u002F08\u002Fgraph-databases-for-beginners-why-a-database-query-language-matters\u002F\"\u003EGraph Databases for Beginners\u003C\u002Fa\u003E por Roberto Zicari (série de 5 artigos).\r\n5. \u003Ca href=\"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=yOYodfN84N4\"\u003EA Skeptics Guide to Graph Databases\u003C\u002Fa\u003E por David Bechberger","excerpt":"\u003Cp\u003EÉ espantosa a popularização que as novas tecnologias de dados alcançaram. A utilização de Grafos para análise de dados e o SQL Server…\u003C\u002Fp\u003E\n","link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server\u002Fbate-bola-com-grafos-e-sql-server-parte-1-definindo-o-modelo","date":"13 mar, 2020","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F08\u002F24172315\u002F1768.sql_logob.jpg","externalMention":"","author":{"id":"452","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2018\u002F05\u002F30184745\u002FwagnercriveliniP-128x128.jpeg","name":"Wagner Crivelini","description":"Consultor Sênior na Microsoft, na área de Data Insights para América Latina. Especialista em bancos de dados, é colunista em diversos portais de TI do Brasil e do exterior, com mais de 100 artigos técnicos publicados. É também co-produtor do DatabaseCast, primeiro podcast brasileiro sobre bancos de dados.","slug":"wagner-crivelini","url":"https:\u002F\u002Fimasters.com.br\u002Fperfil\u002Fwagner-crivelini","registered":"2010-12-30 11:28:37","social":{"linkedin":null,"youtube":null,"facebook":"","twitter":"https:\u002F\u002Ftwitter.com\u002Fwcrivelini@gmail.com","instagram":null,"github":null,"url":"http:\u002F\u002Fwww.wcrivelini.com.br","mail":"wcrivelini@gmail.com"},"articles_count":87,"views_count":756900,"certifications":null,"conquests":null,"office":null},"categories":[{"title":"SQL Server","slug":"sql-server","id":7212,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server"}],"tags":[{"title":"sql server","slug":"sql-server-2","id":324,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server-2"}],"relateds":[],"seo":[],"type":"post"}],"totalArticles":87,"maxPages":9,"page":1,"isFetchingPagination":false},"category":{"success":false,"data":{}},"categoryArticles":{"success":false,"isFetchingPagination":false,"maxPages":0,"page":1,"data":{}},"categoryMostRead":{"success":false,"data":{}},"home":{"success":false,"featured":[],"options":{"homeProducts":[]},"allCategories":{},"featuredArticles":{},"magazines":{"data":[]},"tv":{},"forums":[],"authorsRanking":{},"events":{},"certificatedUsers":[],"news":[]},"page":{"success":false,"data":{}},"magazine":{"success":false,"magazines":[]},"schedule":{"success":false,"data":{}},"searchResult":{"success":false,"totalPosts":0,"totalPage":0,"currentPage":1,"posts":[],"term":"","orderBy":"recents","currentFilter":"articles","isLoading":true,"isLoadingPagination":false},"singleNews":{"success":false,"data":{}},"listNews":{"success":false,"isFetchingPagination":false,"maxPages":0,"page":1,"data":[]},"sponsors":{"success":false,"data":{}},"header":{"success":true,"menus":{"main":[{"ID":138755,"order":1,"parent":0,"title":"Back-End","url":"https:\u002F\u002Fimasters.com.br\u002Fback-end","attr":"package","target":"","classes":"package","xfn":"","description":"Tecnologias utilizadas no backend da aplicação","object_id":7158,"object":"category","type":"taxonomy","type_label":"Categoria","children":[]},{"ID":138756,"order":2,"parent":0,"title":"Mobile","url":"https:\u002F\u002Fimasters.com.br\u002Fmobile","attr":"package","target":"","classes":"package","xfn":"","description":"Conteúdos sobre Desenvolvimento Mobile nas plataformas iOS (iPhone e iPad) e Android.","object_id":4255,"object":"category","type":"taxonomy","type_label":"Categoria","children":[]},{"ID":139476,"order":3,"parent":0,"title":"Front End","url":"https:\u002F\u002Fimasters.com.br\u002Ffront-end","attr":"package","target":"","classes":"package","xfn":"","description":"Conteúdos sobre HTML5, CSS3, Javascript, JQuery, Web Standards e SEO.","object_id":7304,"object":"category","type":"taxonomy","type_label":"Categoria","children":[]},{"ID":138764,"order":4,"parent":0,"title":"DevSecOps","url":"https:\u002F\u002Fimasters.com.br\u002Fdevsecops","attr":"package","target":"","classes":"package","xfn":"","description":"","object_id":1,"object":"category","type":"taxonomy","type_label":"Categoria","children":[]},{"ID":139204,"order":5,"parent":0,"title":"Design & UX","url":"https:\u002F\u002Fimasters.com.br\u002Fdesign-ux","attr":"package","target":"","classes":"package","xfn":"","description":"Conteúdos sobre User Experience, Arquitetura de Informação, Usabilidade, Acessibilidade, Design Responsivo, Teoria do Design e Photoshop.","object_id":7252,"object":"category","type":"taxonomy","type_label":"Categoria","children":[]},{"ID":138759,"order":6,"parent":0,"title":"Data","url":"https:\u002F\u002Fimasters.com.br\u002Fdata","attr":"package","target":"","classes":"package","xfn":"","description":"Conteúdos sobre Banco de Dados Oracle, MySQL, SQL Server, MongoDB, DB2 e Postgre SQL, sobre BI e análise de dados.","object_id":16,"object":"category","type":"taxonomy","type_label":"Categoria","children":[]},{"ID":138758,"order":7,"parent":0,"title":"APIs e Microsserviços","url":"https:\u002F\u002Fimasters.com.br\u002Fapis-microsservicos","attr":"package","target":"","classes":"package","xfn":"","description":"Dicas e tutoriais sobre APIs públicas como Facebook, Twitter, PayPal, Buscapé, Google, etc e arquitetura de microsserviços, com códigos de exemplo, vídeos, cursos.","object_id":4257,"object":"category","type":"taxonomy","type_label":"Categoria","children":[]}],"secondary":[{"ID":138752,"order":1,"parent":0,"title":"Fórum iMasters","url":"https:\u002F\u002Fforum.imasters.com.br\u002F","attr":"","target":"_blank","classes":"","xfn":"","description":"","object_id":138752,"object":"custom","type":"custom","type_label":"Link personalizado","children":[]},{"ID":139067,"order":2,"parent":0,"title":"Portal E-Commerce Brasil","url":"http:\u002F\u002Fwww.ecommercebrasil.com.br","attr":"","target":"","classes":"","xfn":"","description":"","object_id":139067,"object":"custom","type":"custom","type_label":"Link personalizado","children":[]},{"ID":156289,"order":3,"parent":0,"title":"iMasters Business","url":"http:\u002F\u002Fbusiness.imasters.com.br","attr":"","target":"","classes":"","xfn":"","description":"","object_id":156289,"object":"custom","type":"custom","type_label":"Link personalizado","children":[]}]}},"webinar":{"success":false,"data":{}},"webinars":{"success":false,"isFetchingPagination":false,"maxPages":0,"page":1,"data":{"next":[],"prev":[]}},"tv":{"sectionNameLeft":{"small":"Vídeos","large":"iMasters TV"},"itemsLeft":[{"text":"Em Destaque","slug":"recents"},{"text":"Mais Vistos","slug":"most-viewed"}],"sectionNameRight":{"small":"","large":""},"itemsRight":[{"text":"Mais Recentes","slug":"recents"},{"text":"7Masters","slug":"7-masters"},{"text":"PHP Experience","slug":"php-experience"},{"text":"Android DevConference","slug":"android-devconference"},{"text":"Busca","slug":"search"}],"currentVideo":"recents","currentListVideo":"recents"}} window.__SERVER_VARS__ = {"applicationRestUrl":"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-json","applicationBaseUrl":"https:\u002F\u002Fadmin.imasters.com.br"}