Dica do Mês – Concatenando a relação de municípios por Estados através do uso da função Stuff()


Bom dia, boa tarde, boa noite…. Olá pessoal!

Tudo bem? Estou de volta neste finalzinho de férias de começo de ano, com mais um post da sessão Dica do Mês. Você já está preparado para volta as aulas?

Com certeza, todo meu planejamento de atividades, provas, exercícios, seminários, entre outros estão prontos, dediquei os primeiros dias deste mês de janeiro justamente para isso, gosto de me antecipar justamente para ter tempo hábil caso seja necessário fazer alguma alteração.

A primeira dica do mês de 2020 não se relaciona com volta as aulas, na verdade ela surgiu nos últimos dias devido a um estudo que estou fazendo para minha dissertação de mestrado, algo que ainda se encontra meio nebuloso na minha cabeça.

Venho desde o ano de 2017 acompanhando mudanças climáticas nas regiões, estados e municípios do nosso Brasil, o que me fez em 2018 montar um ambiente de estudo com dados reais e hipotéticos para aplicar alguns modelos matemáticos afim de obter dados que possam ser estudados em relação as queimadas ocorridas em pontos específicos.

Dentre estes dados armazenados tenho uma tabela que contempla um pequeno cadastro de Estado, Municípios e Regiões que utilizo em um outro ambiente de Data Warehouse, com base, na metodologia ROLAP (Relational On Line Analitical Processing), técnica que possibilita construir uma estrutura baseada no conceito relacional aplicada a forma de processamento analítica.

Foi baseado mais uma vez neste cenário, em conjunto com os estudos que constantemente venho fazendo que elaborei a ideia para ser apresentada neste post, o qual tem o objetivo básico de demonstrar como podemos fazer uso da função para trabalhar com caracteres string Stuff() existente no Microsoft SQL Server 2008 como podemos concatenar para cada linha de Estados armazenados em minha respectiva tabela a sua lista de municípios, em adicional a quantidade de municípios existentes nesta relação de acordo com o respectivo estado.

Desta forma, sem mais delongas, espero conseguir mitigar a sua curiosidade e apresentar algo interessante. Seja bem-vindo ao post – Dica do Mês – Concatenando a relação de municípios por Estados através do uso da função Stuff().

Continue Lendo “Dica do Mês – Concatenando a relação de municípios por Estados através do uso da função Stuff()”

Dica do Mês – Identificando os números ausentes em uma sequência numérica


Olá pessoal, bom dia.

Tudo bem? Estamos no ultimo final de semana do mês de Setembro, a primavera chegou, já estamos vivendo a última estação do ano, 2019 voando, passando de forma extremamente rápida, o que muitas vezes não nos deixa perceber o quanto nossa vida é uma correria.

Mesmo com este correira, temos que tentar aproveitar todo tempo disponível dentro das 24 horas diárias para se dedicar também ao que gostamos de fazer, e por isso estou aqui novamente em mais um post do meu blog, que honra ter encontrar aqui neste sábado, sua presença é muito importante.

Ainda mais na sessão Dica do Mês, a qual foi criada á alguns anos com objetivo de compartilhar algo que possa ser considerada como uma dica ou melhores práticas para se trabalhar na área de banco de dados, mais especificamente com o Microsoft SQL Server.

A dica de hoje esta envolvida diretamente com os dados manipulados diariamente por empresas, instituições ou organizações públicas e privadas, me refiro a lançamento feitos através de um SIG – Sistema de Informação Gerencial ou ERP – Enterprise Resource Planning, que muitas vezes utilizamos para dar entrada em lançamento contábeis, movimentações fiscais e financeiras, ou “basicamente” cadastrar uma nota fiscal de recebimento de produto no almoxarifado da empresa.

Para facilitar o entendimento, e server como base de exemplo para nossa dica, dentre as mais diversas áreas, setores e departamentos que constituem uma empresa, selecione para esta dica, uma das mais tradicionais áreas conhecida por muitos como Controle de Estoque vinculado com os lançamentos contábeis.

Mais ainda não ficou claro o objetivo desta dica, não é mesmo? Tenho a certeza que não, mas tenha calma, você vai descobrir a seguir o que estou querendo te apresentar.

Continue Lendo “Dica do Mês – Identificando os números ausentes em uma sequência numérica”

Dica do Mês – Analisando o comportamento do comando DBCC CleanTable.


Olá, bom dia. Tudo bem?

O frio já chegou na sua região? Aqui em São Roque, interior de São Paulo, hoje esta manhã esta sendo considerada até o presente momento a mais fria do ano (eu particularmente adoro o frio).

Fico extremamente contente e honrado com a sua visita ao meu blog, mesmo com todo este frio ter a sua presença aqui é muito importante, ainda mais neste post da sessão Dica do Mês, a qual foi criada á alguns anos com objetivo de compartilhar algo que possa ser considerada como uma dica ou melhores práticas para se trabalhar na área de banco de dados, mais especificamente falando relacionadas ao Microsoft SQL Server.

Posso dizer que o post de hoje é algo bastante simples, vamos conhecer um pouco mais sobre um dos mais tradicioais comandos pertencentes a categoria DBCC – Database Command Console existente no Microsoft SQL Server desde suas versões iniciais.

Estou me referindo ao comando DBCC CleanTable, considerado por muitos DBAs o “Veja, aquele produto de limpeza que utilizamos para tirar a gordura dos fogões e panelas”, ele faz basicamente isso em nossas tabelas. No decorrer deste post vou tentar mostrar como Podemos fazer isso.

Sendo assim, sem mais delongas, vamos em frente, vou tentar mitigar a sua curiosidade e ao mesmo também satisfazer os meus objetivos. Seja bem-vindo ao post – Dica do Mês – Analisando o comportamento do comando DBCC Clean Table.


Introdução

O Microsoft SQL Server apresenta em sua galeria de comandos um conjunto muito particular e exclusivo denominado DBCC – Database Command Console em uma possível tradução para o Português “Comandos de Console de Banco de Dados“, pois bem, este conjunto com categoria de comandos é composta por uma relação bem interessante e diversificada que nos permite fazer uso em diversos cenários, dentre eles por exemplos os comandos: DBCC CheckDB ou DBCC ShrinkFile, ambos muito conhecidos pelos DBAs e Administradores de Banco de Dados, caso você ainda não conheça, com certeza em algum momento terá a oportunidade.

Como já destaquei nesta relação exclusiva de comandos, podemos se deparar com um deles que nos permite aplicar sem qualquer tipo de alteração de configuração, ou mudanças drásticas na estrutura de nosso banco de dados, o que chamamos de remover a gordura de nossas tabelas, talvez você não consiga ou não esteja entendendo o que eu estou definindo como “gordura”, na verdade me refiro por exemplo a aquelas colunas do tipo de dados VarChar, criadas inicialmente em nossas tabelas, mas que ao longo do tempo se tornam colunas praticamente consideradoras espúrias (algo sem sentido ou desnecessário), é ai que entra o nosso amigo DBCC CleanTable, ele tem um papel único e específico justamente para este tipo de cenário, que daqui a pouco eu vou demonstrar, mas antes vamos conhecer um pouquinho sobre este comando.

DBCC CleanTable

Adicionado ao Microsoft SQL Server a partir da edição 2008, o comando DBCC CleanTable possui como papel principal a capacidade de recuperar e liberar o espaço ocupado por colunas existentes em uma tabela consideradas colunas com comprimento variável quando utilizam os seguintes tipos de dados:

  • Varchar;
  • Nvarchar;
  • Varchar(max);
  • Nvarchar(max);
  • Varbinary;
  • Varbinary(max);
  • Text;
  • Ntext;
  • Image;
  • Sql_variant; e
  • XML.

Ele recupera espaço anteriormente ocupado por um destes tipos de dados, depois que uma coluna de comprimento variável é descartada, mas não recupera espaço depois que uma coluna de comprimento fixo é descartada.

Mesmo não tem a capacidade de recuperar o espaço ocupado em disco logo após este limpeza na estrutura da tabela, o comando DBCC CleanTable, pode ajudar a melhorar ou até mesmo zerar taxas de fragmentação que possam estar sendo apresentadas justamente em uma tabela devido a utilização destas colunas com comprimentos variáveis.

Considerações

  • As colunas descartadas forem armazenadas em linha, DBCC CLEANTABLE recuperará espaço da unidade de alocação IN_ROW_DATA da tabela.
  • Quando as colunas forem armazenadas fora de linha, o espaço será recuperado da unidade de alocação LOB_DATA ou ROW_OVERFLOW_DATA, dependendo do tipo de dados da coluna descartada.Se o espaço recuperado de uma página ROW_OVERFLOW_DATA ou LOB_DATA resultar em uma página vazia, DBCC CLEANTABLE removerá a página. DBCC CLEANTABLE executa como uma ou mais transações.
  • O espaço recuperado de uma página ROW_OVERFLOW_DATA ou LOB_DATA resultar em uma página vazia, DBCC CLEANTABLE removerá a página. DBCC CLEANTABLE executa como uma -ou mais transações.
  • Caso não especificado um tamanho de lote, o comando processará a tabela inteira em uma transação e a tabela será bloqueada exclusivamente durante a operação. Para algumas tabelas grandes, o comprimento da única transação e o espaço do log requeridos podem ser muito grandes. Se um tamanho de lote for especificado, o comando executará em uma série de transações, cada qual incluindo o número especificado de linhas.
  • O comando DBCC CLEANTABLE não pode ser executado como uma transação dentro de outra transação. Essa operação é totalmente registrada. Não há suporte para DBCC CLEANTABLE para uso em tabelas do sistema, tabelas temporárias ou a parte do índice columnstore xVelocity de memória otimizada de uma tabela.

Evite utilizar

O comando DBCC CLEANTABLE não deve ser executado como uma tarefa de manutenção de rotina. Ao invés disso, utilize o DBCC CLEANTABLE depois de fazer mudanças significativas em colunas de comprimento variável em uma tabela ou exibição indexada e necessita recuperar o espaço sem-uso (considerada como área não alocada) prontamente.

Alternativas para o uso do DBCC CleanTable

Uma das possíveis alternativas quando desejamos recuperar o espaço ocupado por colunas de comprimemto variável aplica-se a reconstrução de índices em tabelas ou visões indexadas, mas este recurso pode ser considerado custoso no que se relaciona ao tempo de processamento ou até mesmo alocação de recursos durante sua execução.

Pois bem, agora que já conhecemos um pouco sobre este comando, suas considerações, o quando usar e não usar, vamos avançar um pouco este post, dando início a nosso cenário de estudos afim de analisarmos de uma forma bem simples e artificial como o DBCC CleanTable pode nos ser útil.


NOSSO AMBIENTE

Como de costume vamos utilizar um ambiente isolado dos demais bancos de dados que você possa conter, desta maneira nosso cenário será constituído dos seguintes elementos:

Observações

  1. Estaremos fazendo uso de um arquivo texto, o qual é parte importante para nossa análise. O mesmo possui os dados que serão importados para o Microsoft SQL Server, contendo com conjunto real de valores coletados através do portal do INPEInstituto Nacional de Pesquisas Especiais, através de seu Banco de Dados de análise de queimadas ocorridas no Brasil ao longo dos últimos 70 anos, sendo considerada uma das mais importantes fontes de dados abertos do Brasil, disponível para qualquer tipo de análise. Particularmente falando, sou um grande admirador do trabalho realizado pelo INPE, o qual eu comecei em 2017 a estudar para um dos meus projetos no mestrado e diretamente relacionados com a minha nova área de estudos: Data Warehouse, Data Mining e BI.
  2. A estrutura apresentada no arquivo texto, não tem por finalidade ou regra ser considerada uma estrutura padronizada, como também, algo que atenda as regras da Normalização, longe disso, todo conjunto de dados, tipos de dados, nomes das colunas e sua composição física e lógica foi definida e criada para atender as regras de negócio muito específicas de um trabalho de mestrado acadêmico, o qual não faz parte deste estudo ou análise.
  3. O objetivo deste post não se realiza a apresentar, demonstrar ou orientar como realizar o procedimento de importação de dados para o Microsoft SQL Server, sendo assim, caso você tenha dúvidas ou dificuldades para realizar este procedimento, acesse: Import and Export Data with the SQL Server Import and Export Wizard.
  4. Logo após a execução do processo de importação dos dados, você notará que nossa tabela e sua estrutura foi criada sem respeitar uma análise de uso de tipos de dados, criação de chaves primárias ou outras considerações que podemos definir como melhores práticas de modelagem de banco de dados. Não foi fique preocupado, pois estaremos realizando toda esta reestruturação logo na sequência.

Avançando mais um pouco, vamos criar nosso banco de dados e logo na sequência começaremos nossa análise, para tais procedimentos, utilizaremos o Bloco de Código 1 abaixo:

— Bloco de Código 1 – Criando nosso cenário —

— Criando o Banco de Dados —

Create Database TesteDBCCCleanTable
Go

— Acessando o Banco de Dados —

Use TesteDBCCCleanTable
Go

Presumo que neste momento você já tenha feito download do arquivo QueimadasTableCleanTable.txt, como também, já tenha realizado a importação dos dados e criação da tabela,.

Ótimo, espero que todo processo de importação de dados tenha ocorrido corretamente, agora com a estrutura criada e acessível, teremos a possibilidade de começar a realizar nossa análise, nosso próximo passo será reestrutura a tabela QueimadasCleanTable, definindo sua chave primária, alterando tipos de dados em determinadas colunas, removendo outras, enfim colocando um pouco de ordem na casa.

Desta forma, vamos utilizar o Bloco de Código 2 a seguir:

— Bloco de Código 2 – Reestruturando a Tabela QueimadasCleanTable —

— Remover a Anulabilidade da coluna CodigoQueimada —
Alter Table QueimadasCleanTable
Alter Column CodigoQueimada Int Not Null
Go
— Adicionar a coluna chave primária na Tabela QueimadasCleanTable —
Alter Table QueimadasCleanTable
Add Constraint [PK_QueimadasCleanTable_Codigo]
Primary Key (CodigoQueimada)
Go
— Alterando o Tamanho e Tipo de Dados da Coluna Pais —
Alter Table QueimadasCleanTable
Alter Column Pais Char(6) Not Null
Go
— Alterando os tipos de dados e tamanho da coluna Satelite —
Alter Table QueimadasCleanTable
Alter Column Satelite Varchar(10) Not Null
Go
— Alterando os tipos de dados e tamanho das colunas —
Alter Table QueimadasCleanTable
Alter Column Municipio Varchar(40) Not Null
Go
Alter Table QueimadasCleanTable
Alter Column Estado Varchar(20) Not Null
Go
Alter Table QueimadasCleanTable
Alter Column Bioma Varchar(15) Not Null
Go
— Alterando o formato do dado armazenado na coluna DataHora —
Update QueimadasCleanTable
Set DataHora=Convert(DateTime, DataHora, 102)
Go
— Alterando a Coluna DataHora —
Alter Table QueimadasCleanTable
Alter Column DataHora DateTime Not Null
Go
— Alterando a Coluna Longitude —
Alter Table QueimadasCleanTable
Alter Column Longitude Numeric(10,5) Not Null
Go
— Alterando a Coluna Latitude —
Alter Table QueimadasCleanTable
Alter Column Latitude Numeric(10,5) Not Null
Go

Ufa, após este longo caminho percorrido, nossa tabela QueimadasCleanTable, deve estar apresentando uma estrutura similar a Figura 1:


Figura 1 – Banco de Dados TesteDBCCCleanTable e Tabela QueimadasCleanTable criados.

Sensacional, agora a brincadeira vai começar, devemos ter basicamente 752.252 (Setecentas e cinquenta e duas mil, duzentas e cinquenta e duas) linhas de registros lógicos inseridas nesta tabela, uma massa de dados interessante e bem diversificada para nosso estudo, afim de confirmarmos nossas massa de dados, vamos executar o Bloco de Código 3 a seguir, para retornarmos em tela uma pequena porção de dados:

— Bloco de Código 3 – Validando uma porção de dados da Tabela QueimadasCleanTable —

Select Top 1000 DataHora,
Satelite,
Pais,
Estado,
Municipio
From QueimadasCleanTable
Go

Após a execução do Bloco de Código 3, você deverá ter obtido em tela, um resultado similar ao apresentado abaixo pelo Figura 2:

Figura 2 – Dados coletados e apresentados em tela após a execução do Bloco de código 3.

Por enquanto nenhuma novidade, nada em especial foi apresentado, não é mesmo? Eu acredito que sim. Agora que toda estrutura da tabela foi refeita, nossos dados foram validados, o que pode estar faltando para fazermos uso do comando DBCC CleanTable?

A resposta é simples, falta identificar quais são as colunas de comprimento variável existentes em nossa tabela que poderemos utilizar para entender o comportamento deste comando, sendo assim, nosso próximo passo será identificar quais seriam as colunas e seus respectivos tipos de dados que formam a estrutura da tabela QueimadasCleanTable, através da execução do Bloco de Código 4 apresentado abaixo:

— Bloco de Código 4 – Identificando as colunas de comprimento variável —

Select st.name As ‘TableName’,
sc.name As ‘ColumnName’,
sc.column_id As ‘ColumnID’,
sty.name As ‘DataType’,
sc.max_length As ‘MaxLength’
from sys.tables st Inner Join sys.columns sc
on st.object_id = sc.object_id
Inner Join sys.systypes sty
on sc.system_type_id = sty.xtype
Where st.name = ‘QueimadasCleanTable’
And sty.name = ‘VarChar’
Order By st.Name Asc, sc.column_id Asc
Go

Note que estamos fazendo uso das conhecidas e tradicionais tabelas de sistema:

  • sys.tables;
  • sys.columns; e
  • sys.systypes.

A execução do Bloco de Código 4 é simples e rápida, a Figura 3 abaixo, deve ilustrar o resultado obtido após sua execução:

Figura 3 – Relação de colunas que utilizam o tipo de dados Varchar() com tamanho variáveis.

Estamos quase lá, já sabemos da existência de 7(sete) colunas que neste momento fazem parte da estrutura da nossa tabela QueimadasCleanTable que nos possibilitam serem utilizadas.

Como eu destaquei anteriormente o comando DBCC CleanTable tem como papel principal recuperar o espaço ocupado por estas colunas, quando as mesmas venham a ser removidas ou sofram alterações em seus tamanhos.

Para que possamos entender de forma clara e didática como o DBCC CleanTable trabalha, temos a necessidade de identificar os espaços ocupados neste momento por nossa tabela, e obrigatoriamente as taxas de alocação e fragmentação de dados, vamos então executar o Bloco de Código 5, o qual vai nos ajudar a identificar o espaçamento ocupado por nossa tabela:

— Bloco de Código 5 – Identificando o espaço e áreas de alocação ocupadas pela Tabela QueimadasCleanTable —

— Identificando os espaços ocupados —
sp_spaceused ‘QueimadasCleanTable’
Go
— Identificando as taxas de alocação, fragmentação e distribuição de registros —
Select object_name(ddips.object_id) As ‘Tabela’,
si.name As ‘Índice’,
convert(decimal(5,2),isnull(ddips.avg_fragmentation_in_percent,0)) As ‘% Média de Fragmentação’,
convert(decimal(5,2),isnull(ddips.avg_page_space_used_in_percent,0)) As ‘% Média de Espaço utilizado’,
ddips.page_count As ‘Páginas’,
ddips.compressed_page_count As ‘Páginas compactadas’,
ddips.record_count As ‘Registros’,
ddips.ghost_record_count As ‘Registros Fantasmas’
From sys.dm_db_index_physical_stats(db_id(), object_id(‘QueimadasCleanTable’),null, null, ‘detailed’) ddips Inner Join sys.indexes si
on si.object_id = ddips.object_id
Go
Acredito que você deve ter observado que o Bloco de Código 5 foi dividido em duas partes, a primeira fazendo uso da System Stored Procedure: SP_SpaceUsed, e a segunda, através da DMF – Dynamic Management Function – sys.dm_db_index_physical_stats.
Como uma forma de ajudar a identificar e entender os dados coletados após a execução deste bloco de código, apresenta abaixo a Tabela 1 com os dados coletados através SP_SpaceUsed e Tabela 2 com os dados coletados através sys.dm_db_index_physical_stats.
Tabela 1 – SP_SpaceUsed – Espaços Ocupados
name rows reserved data index_size unused
QueimadasCleanTable 752252 81736 KB 81272 KB 312 KB 152 KB
Ao realizarmos uma breve análise, podemos observar através dos resultados apresentados na Tabela 1, que nosso tabela QueimadasCleanTable, neste momento esta ocupando uma área em disco de quase 82Mbs (Megabytes), sendo 81.2Mbs para dados e 312Kbs (Kilobytes) para índices, com uma área não alocada de 152Kbs.
Tabela 2 – Sys.dm_db_index_physical_stats – Taxas de Fragmentação, Distribuição de Páginas de Dados e Registros
Tabela Índice % Média de Fragmentação % Média de Espaço utilizado Páginas Páginas compactadas Registros Registros Fantasmas
QueimadasCleanTable PK_CodigoQueimada_Queimadas2018_CleanTable 0.01 99.34 10159 0 752252 0
QueimadasCleanTable PK_CodigoQueimada_Queimadas2018_CleanTable 0.00 44.07 37 0 10159 0
QueimadasCleanTable PK_CodigoQueimada_Queimadas2018_CleanTable 0.00 5.92 1 0 37 0
Já os dados apresentados pela Tabela 2, mostram uma pequena taxa de fragmentação de 0,01 % para nosso índice chave primária: PK_CodigoQueimada_Queimadas2018_CleanTable, em sua área de alocação de dados, composta por 10.159 páginas de dados.
Estamos próximos da hora da verdade, com todo esta conjunto de dados coletados, poderemos comprovar como o DBCC CleanTable pode nos ajudar, através do Bloco de Codigo 6, realizaremos a exclusão de 4 (Municipio, Bioma, AreaIndu e FRP) das 7 colunas listadas anteriormente, logo na sequência vamos repetir a execução do Bloco de Código 5 para comprovar que as áreas e espaços ocupados continuam apresentando os mesmos valores, e nosso ultimo passo será executar o DBCC Clean Table.
— Bloco de Código 6 – Removendo as colunas Municipio, Bioma, AreaIndu e FRP —
Alter Table QueimadasCleanTable
Drop Column Municipio, Bioma, AreaIndu, FRP
Go
As colunas foram removidas corretamente, agora vamos repetidar a execução do Bloco de Código 5 na sequência.
— Executar novamente o Bloco de Código 5 —
— Identificando os espaços ocupados —
sp_spaceused ‘QueimadasCleanTable’
Go
— Identificando as taxas de alocação, fragmentação e distribuição de registros —
Select object_name(ddips.object_id) As ‘Tabela’,
si.name As ‘Índice’,
convert(decimal(5,2),isnull(ddips.avg_fragmentation_in_percent,0)) As ‘% Média de Fragmentação’,
convert(decimal(5,2),isnull(ddips.avg_page_space_used_in_percent,0)) As ‘% Média de Espaço utilizado’,
ddips.page_count As ‘Páginas’,
ddips.compressed_page_count As ‘Páginas compactadas’,
ddips.record_count As ‘Registros’,
ddips.ghost_record_count As ‘Registros Fantasmas’
From sys.dm_db_index_physical_stats(db_id(), object_id(‘QueimadasCleanTable’),null, null, ‘detailed’) ddips Inner Join sys.indexes si
on si.object_id = ddips.object_id
Go
A Figura 4, vai ilustrar e comprovar que os valores apresentados após a nova execução do Bloco de Código 5, são os mesmos obtidos em sua primeira execução:
Figura 4 – Valores obtidos após a segunda execução do Bloco de Código 5.
E agora chegou o grande momento, vamos executar o Bloco de Código 7, o qual terá a responsabilidade de executar o comando DBCC CleanTable, logo na sequência vamos executar novamente o Bloco de Código 5, e ai sim teremos uma surpresa:
— Bloco de Código 7 – Executando o comando DBCC CleanTable —
Dbcc CleanTable(TesteDBCCCleanTable,’dbo.QueimadasCleanTable’)
Go
Por padrão como boa parte dos comandos DBCCs, o CleanTable, vai retornar na guia de mensagens a seguinte frase:
DBCC execution completed. If DBCC printed error messages, contact your system administrator.”
Agora repita novamente a execução do Bloco de Código 5, e observe que teremos um novo conjunto de valores apresentados.
— Executar novamente o Bloco de Código 5 —
— Identificando os espaços ocupados —
sp_spaceused ‘QueimadasCleanTable’
Go
— Identificando as taxas de alocação, fragmentação e distribuição de registros —
Select object_name(ddips.object_id) As ‘Tabela’,
si.name As ‘Índice’,
convert(decimal(5,2),isnull(ddips.avg_fragmentation_in_percent,0)) As ‘% Média de Fragmentação’,
convert(decimal(5,2),isnull(ddips.avg_page_space_used_in_percent,0)) As ‘% Média de Espaço utilizado’,
ddips.page_count As ‘Páginas’,
ddips.compressed_page_count As ‘Páginas compactadas’,
ddips.record_count As ‘Registros’,
ddips.ghost_record_count As ‘Registros Fantasmas’
From sys.dm_db_index_physical_stats(db_id(), object_id(‘QueimadasCleanTable’),null, null, ‘detailed’) ddips Inner Join sys.indexes si
on si.object_id = ddips.object_id
Go
As tabelas 3 e 4 apresentadas na sequência, vamos nos ajudar a identificar estes novos valores apresentados após a execução do Bloco de Código 7:
Tabela 3 – SP_SpaceUsed – Espaços Ocupados
name rows reserved data index_size unused
QueimadasCleanTable 752252 81736 KB 81272 KB 312 KB 152 KB
Ao analisarmos os valores apresentados na Tabela 3, inicialmente podemos ficar surpresos por não ocorreram mudanças, na verdade não vai ocorrer mesmo, pois como destacado no início deste post o DBCC CleanTable não tem a função de liberar o espaço físico e lógico ocupado pela tabela e suas estruturas.
Tabela 4 – Sys.dm_db_index_physical_stats – Taxas de Fragmentação, Distribuição de Páginas de Dados e Registros
Tabela Índice % Média de Fragmentação % Média de Espaço utilizado Páginas Páginas compactadas Registros Registros Fantasmas
QueimadasCleanTable PK_CodigoQueimada_Queimadas2018_CleanTable 0.01 80.99 10159 0 752252 0
QueimadasCleanTable PK_CodigoQueimada_Queimadas2018_CleanTable 0.00 44.07 37 0 10159 0
QueimadasCleanTable PK_CodigoQueimada_Queimadas2018_CleanTable 0.00 5.92 1 0 37 0
Por outro lado, a Tabela 4 nos apresenta uma pequena mudança na coluna % Média de Espaço Utilizado que agora é de 80,99 % e antes era de 99,34%, ou seja, ao realizarmos a execução das colunas: Municipio, Bioma, AreaIndu e FRP o DBCC CleanTable realizou uma pequena recuperação de espaço que estava sendo ocupados por estas colunas em suas respectivas linhas de registro lógicos.
Isso não é algo fora do comum, conseguir reaproveitar as áreas que estavam sendo ocupadas anteriormente sem precisar realizar qualquer tipo de reconstrução ou mudanças de configuração. Eu acredito que sim.
Seguindo a tradição dos posts desta sessão, antes de encerrarmos, gostaria de contar com a sua participação neste post, respondendo a enquete abaixo:
Quero propor um desafio
Elabore um cenário similar ao apresentado aqui, e utilize os comandos Delete e Truncate Table em conjunto com o DBCC CleanTable, faça uma análise comparativa, tenho a certeza que este desafio vai lhe ajudar a entender de forma simples e objetiva as diferenças entre o Delete e o Truncate, sendo esta, uma das dúvidas mais recorrentes que podemos encontrar na internet.
Com isso chegamos ao final de mais um post da sessão Dica do Mês, espero que você tenha gostado, eu como de costume gostei muito. 

REFERÊNCIAS

https://docs.microsoft.com/en-us/sql/t-sql/database-console-commands/dbcc-cleantable-transact-sql

https://docs.microsoft.com/pt-br/sql/relational-databases/system-stored-procedures/sp-spaceused-transact-sql

https://docs.microsoft.com/pt-br/sql/relational-databases/system-stored-procedures/sp-columns-transact-sql

https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-db-index-physical-stats-transact-sql

https://docs.microsoft.com/en-us/sql/relational-databases/system-compatibility-views/sys-systypes-transact-sql

https://docs.microsoft.com/en-us/sql/t-sql/data-types/data-types-transact-sql

POSTS ANTERIORES

CONCLUSÃO

Como de costume, tenho um imenso prazer em poder compartilhar um pouco das minhas experiências, estudos e conhecimentos que estou diariamente formando sobre este fantástico Sistema Gerenciador de Banco de Dados chamado Microsoft SQL Server.

Neste post, tivemos a possibilidade de relembrar um pouco sobre os comandos DBCCs, mais especificamente o DBCC CleanTable, conhecido como o “Veja, desengordurante, das estruturas de tabelas e visões índexadas” existente no Microsoft SQL Server.

O uso desta comando pode ser aplicado, como uma ferramenta de apoio quando temos a necessidade de reaproveitar o espaço antes ocupado por áreas que pertenciam a uma ou mais colunas que venham a utilizar tipos de dados com tamanhos variáveis.

O comando DBCC CLEANTABLE não deve ser executado como uma tarefa de manutenção de rotina, mas sim, como um recurso aplicado em momento específicos e não de uso contínuo.

Através do cenário aqui apresentado, foi possível observar, como este comando é capaz de resdistribuir e aproveitar o espaço ocupado internamente, sem nos forçar a realizar alterações drásticas em nossas tabelas, bem como, mudanças nas configurações do nosso banco de dados ou SQL Server.

Este é o fantástico Microsoft SQL Server, produto tão fascinante que a cada dia eu não consigo deixar de querer estudar e conhecer mais ainda.

Agradecimentos

Agradeço a você por sua atenção e visita ao meu blog. Fique à vontade para enviar suas críticas, sugestões, observações e comentários.

Nos encontramos no próximo post da sessão Dica do Mês a ser publicado em breve.

Um forte abraço.

Até mais.

Dica do Mês – Como ficar “quase louco” utilizando análise combinatória no Microsoft SQL Server


Olá, boa noite.

Estamos no mês de março, carnaval já passou, o primeiro trimestre de 2019 está acabando, e para minha alegria te encontro mais uma vez no meu blog, caso esta seja a sua primeira visita ou acesso, fico mais feliz ainda, seja muito bem-vindo.

Este é mais um post da sessão Dica do Mês, sessão dedicada a compartilhar bimestralmente dicas, novidades, curiosidades e demais assuntos, conteúdos e informações relacionadas ao Microsoft SQL Server, Banco de Dados e Tecnologias de Banco de Dados.

No post de hoje, quero compartilhar com vocês a minha mais nova “loucura” criada em meus ambientes de estudos acadêmicos para ser utilizada no Microsoft SQL Server através do uso da Análise Combinatória, isso mesmo mais uma vez a matemática esta presente em nossas vidas e desta vez foi justamente para permitir a criação de um script que permite criar todas as sequência de combinações de letras e números afim de construir um gerador de placas de carros para todos os estados brasileiros.

 

Não parece realmente coisa de louco, minha esposa disse que sim, eu também acho (kkkkk).

Pois bem, ficou curioso para saber como eu criei mais esta “loucura”? Calma, daqui a pouco eu conto mais sobre isso para você.

Sendo assim, sem mais delongas, vamos em frente, vou tentar mitigar a sua curiosidade e ao mesmo também satisfazer os meus objetivos. Seja bem-vindo ao post – Dica do Mês – Como ficar “quase louco” utilizando análise combinatória no Microsoft SQL Server.


Introdução

Muito se fala que a área de banco de dados, e posteriormente os Sistemas Gerenciadores de Bancos de Dados (SGBDs) nasceram dos métodos, técnicas e também das teorias existentes na Matemática.

A cada dia eu tenho mais certeza que esta analogia é verdadeira, e neste post, eu pretendo justamente mostrar como mais uma vez esta fantástica e grandiosa área de estudos e conhecimentos pode nos ajudar a transformar algo que parece ter um nível de raciocínio tão complexo ou talvez impossível, em algo na verdade simples, fácil e de rápida compreensão.

Para ser mais direto, estou me referindo a análise combinatória, uma das mais variadas áreas de conhecimento e aprendizado existentes na Matemática e que este mero ser humano demorou um bom tempo para conseguir entender de verdade e aplicar de forma bem racional.

ANÁLISE COMBINATÓRIA

Podemos determinar a análise combinatória como sendo um conjunto de possibilidades constituídos por elementos finitos, a mesma baseia-se em critérios que possibilitam a contagem. Realizamos o seu estudo na lógica matemática, analisando possibilidades e combinações.

Por exemplo: Descubra quantos números com 3 algarismos conseguimos formar com o conjunto numérico {1, 2, 3}, olha a teoria de conjuntos aí gente….

  • Conjunto de elementos finito: {1, 2, 3}.
  • Conjunto de possibilidades de números com 3 algarismos: {123, 132, 213, 231, 312, 321}.

A análise combinatória estuda os seguintes conteúdos:

  • Princípio fundamental da contagem;
  • Fatorial;
  • Permutação simples;
  • Permutação com repetição;
  • Arranjo simples; e
  • Combinação simples.

Não vou abortar todos estes conteúdos de estudo utilizado pela análise combinatória neste post, mas sim o que mais entendo como importante e de extrema necessidade para o cenário que estaremos utilizando a posterior, sendo estes:

  • Permutação Simples; e
  • Permutação com repetição.

Permutação simples

Na permutação os elementos que compõem o agrupamento mudam de ordem, ou seja, de posição. Determinamos a quantidade possível de permutação dos elementos de um conjunto, com a seguinte expressão:

Pn = n!
Pn = n . (n-1) . (n-2) . (n-3)…..1!

Exemplo: Em uma eleição para representante de sala de aula, 3 alunos candidataram-se: Fernanda, Eduardo e Malú. Quais são os possíveis resultados dessa eleição?

  • Fernanda (F);
  • Eduardo (E); e
  • Malú (M).

Os possíveis resultados dessa eleição podem ser dados com uma permutação simples, acompanhe:

n = 3 (Quantidade de candidatos concorrendo a representante)

Pn = n!

Pn = 3 . 2 . 1!
Pn = 6

Para a eleição de representante, temos 6 possibilidades de resultado, em relação a posição dos candidatos, ou seja, 1º, 2º e 3º lugar.

Veja a seguir os possíveis resultados dessa eleição:

Resultado 1

Resultado 2 Resultado 3 Resultado 4 Resultado 5 Resultado 6
FEM FME EFM EMF MEF

MFE

 

Permutação com repetição

Nessa permutação alguns elementos que compõem o evento experimental são repetidos, quando isso ocorrer devemos aplicar a seguinte fórmula:

Pn(n1,n2,n3…nk)=n!n1!⋅n2!⋅n3!…nk!

  • Pn(n1,n2,n3…nk) = permutação com repetição
  • n! = total de elemetos do evento
  • n1!⋅n2!⋅n3!…nk! = Elementos repetidos do evento

Exemplo: Quantos anagramas são possíveis formar com a palavra CASA. A palavra CASA possui:
4 letras (n) e duas vogais que se repetem (n1).

  • n! = 4!
  • n1! = 2!

Pn(n1)=n!n1!

Pn(n1)=4!2!

Pn(n1)=4⋅3⋅2⋅1!2⋅1!

Pn(n1)=242=12

Anagramas da palavra CASA sem repetição

CASA

ACSA ASCA ASAC SCAA

CSAA

AASC AACS CAAS SAAC SACA

ACAS

Bom, agora que conhecemos um pouco destes conceitos, você pode estar se perguntando:

“O que o Microsoft SQL Server tem haver com isso?”.

Então, tudo, pois ele faz justamente uso destes elementos e dos demais quando queremos realizar as combinações das mais variadas possíveis que envolvem letras, letras e números, ou somente números.

E aí, até aqui tudo tranquilo? Espero que sim, pois daqui em diante começaremos a preparar nosso ambiente e aplicaremos a análise combinatória e as permutações para colocarmos em funcionamento a minha “loucura”.

Para você ter a ideia do nível de loucura que estaremos trabalhando, ao realizar o uso das vinte e seis letras do alfabeto em nosso idioma da língua portuguesa teremos basicamente a seguinte permutação com repetição:

  • n! = 3!
  • n1! = 26!

Ou seja, de forma mais simples, vamos permutar: 26 letras * 26 letras * 26 letras, o que não apresentara um total de: 17.756 (Dezessete Mil, Setecentos e Cinquenta e Seis) combinações de letras distintas.

Mas não terminamos isso nossa caminhada, depois de realizar estas combinações de letras (17.756), vamos fazer uso dos arranjos (este conteúdo eu não abordei), que nos permitirá criar em tempo real todos os agrupamentos entre letras e números (de 0 até 9999), estabelecendo a seguinte fórmula:

Arranjos = LetrasCombinadas(17756) * Numeracao(0…9999) = 177.542.244

os anagramas que vimos apouco, como por exemplo: AAA-0001, o qual vai nos permitir obter um total de: 177.542.244 (Cento e Setenta e Sete Milhões, Quinhentos e Quarente e Dois Mil, Duzentas e Quarenta e Quatro) agrupamentos ou arranjos únicos e distintos que teremos a disposição para serem armazenados.

Não é algo de louco mesmo?

NOSSO AMBIENTE

Como de costume vamos utilizar um ambiente isolado dos demais bancos de dados que você possa conter, desta maneira nosso cenário será constituído dos seguintes elementos:

  • Banco de Dados: GeradorDePlacas;
  • Tabelas: LetrasCombinadas, Numeracao, Placas e FaixasDePlacasPorEstado;
  • CTEs: CTEMeuAlfabeto; e
  • Stored Procedure: P_PesquisarPlacas.

Criando o ambiente

Através do Bloco de Código 1 apresentado abaixo, vamos realizar a criação dos respectivos elementos destacados anteriormente:

 

— Bloco de Código 1 —

 

— Criando o Banco de Dados —

Create Database GeradorDePlacas

Go

 

— Acessando o Banco de Dados —

Use GeradorDePlacas

Go

 

— Desativando a contagem de linhas —

Set NoCount On

Go

 

— Criando a Tabela LetrasCombinadas para armazenar todas as combinações de Letras —

Create Table LetrasCombinadas

(CodigoSequencialLetrasCombinadas SmallInt Primary Key Identity(1,1) Not Null,

SequencialDeLetrasCombinadas Char(3) Not Null)

Go

 

— Criando a Tabela Numeracao para armazenar a faixa numérica de 1 até 9999 —

Create Table Numeracao

(CodigoNumeracao SmallInt Primary Key Identity(1,1) Not Null)

Go

 

— Criando a Tabela Placas para armazenar o CodigoSequencialLetrasCombinadas e o número da Placa —

Create Table Placas

(CodigoSequencialPlacas Int Primary Key Identity(1,1) Not Null,

CodigoSequencialLetrasCombinadas SmallInt Not Null,

CodigoSequencialNumeroPlacas SmallInt Not Null)

Go

 

— Criando a Tabela FaixasDeFaixasDePlacasPorEstado para armazenar as faixas de placas por Estado —

Create Table FaixasDePlacasPorEstado

(CodigoSequencialFaixasDePlacasPoEstado TinyInt Primary Key Identity(1,1) Not Null,

CodigoSequencialFaixasDeLetrasNumerosInicial Char(7) Not Null,

CodigoSequencialFaixasDeLetrasNumerosFinal Char(7) Not Null,

FaixasDePlacasPorEstadoNomeDoEstado Varchar(30) Not Null)

Go

 

— Inserindo a distribuição de Faixas de Placas Por Estado —

Insert Into FaixasDePlacasPorEstado Values (‘AAA0001′,’BEZ9999′,’Paraná’)

Insert Into FaixasDePlacasPorEstado Values (‘BFA0001′,’GKI9999′,’São Paulo’)

Insert Into FaixasDePlacasPorEstado Values (‘GKJ0001′,’HOK9999′,’Minas Gerais’)

Insert Into FaixasDePlacasPorEstado Values (‘HOL0001′,’HQE9999′,’Maranhão’)

Insert Into FaixasDePlacasPorEstado Values (‘HQF0001′,’HTW9999′,’Mato Grosso do Sul’)

Insert Into FaixasDePlacasPorEstado Values (‘HTX0001′,’HZA9999′,’Ceará’)

Insert Into FaixasDePlacasPorEstado Values (‘HZB0001′,’IAP9999′,’Sergipe’)

Insert Into FaixasDePlacasPorEstado Values (‘IAQ0001′,’JDO9999′,’Rio Grande do Sul’)

Insert Into FaixasDePlacasPorEstado Values (‘JDP0001′,’JKR9999′,’Distrito Federal’)

Insert Into FaixasDePlacasPorEstado Values (‘JKS0001′,’JSZ9999′,’Bahia’)

Insert Into FaixasDePlacasPorEstado Values (‘JTA0001′,’JWE9999′,’Pará’)

Insert Into FaixasDePlacasPorEstado Values (‘JWF0001′,’JXY9999′,’Amazonas’)

Insert Into FaixasDePlacasPorEstado Values (‘JXZ0001′,’KAU9999′,’Mato Grosso’)

Insert Into FaixasDePlacasPorEstado Values (‘KAV0001′,’KFC9999′,’Goiás’)

Insert Into FaixasDePlacasPorEstado Values (‘KFD0001′,’KME9999′,’Pernambuco’)

Insert Into FaixasDePlacasPorEstado Values (‘KMF0001′,’LVE9999′,’Rio de Janeiro’)

Insert Into FaixasDePlacasPorEstado Values (‘LVF0001′,’LWQ9999′,’Piauí’)

Insert Into FaixasDePlacasPorEstado Values (‘LWR0001′,’MMM9999′,’Santa Catarina’)

Insert Into FaixasDePlacasPorEstado Values (‘MMN0001′,’MOW9999′,’Paraíba’)

Insert Into FaixasDePlacasPorEstado Values (‘MOX0001′,’MTZ9999′,’Espírito Santo’)

Insert Into FaixasDePlacasPorEstado Values (‘MUA0001′,’MVK9999′,’Alagoas’)

Insert Into FaixasDePlacasPorEstado Values (‘MVL0001′,’MXG9999′,’Tocantins’)

Insert Into FaixasDePlacasPorEstado Values (‘MXH0001′,’MZM9999′,’Rio Grande do Norte’)

Insert Into FaixasDePlacasPorEstado Values (‘MZN0001′,’NAG9999′,’Acre’)

Insert Into FaixasDePlacasPorEstado Values (‘NAH0001′,’NBA9999′,’Roraima’)

Insert Into FaixasDePlacasPorEstado Values (‘NBB0001′,’NEH9999′,’Rondônia’)

Insert Into FaixasDePlacasPorEstado Values (‘NEI0001′,’NFB9999′,’Amapá’)

Insert Into FaixasDePlacasPorEstado Values (‘NFC0001′,’NGZ9999′,’Goiás’)

Insert Into FaixasDePlacasPorEstado Values (‘NHA0001′,’NHT9999′,’Maranhão’)

Insert Into FaixasDePlacasPorEstado Values (‘NHU0001′,’NIX9999′,’Piauí’)

Insert Into FaixasDePlacasPorEstado Values (‘NIY0001′,’NJW9999′,’Mato Grosso’)

Insert Into FaixasDePlacasPorEstado Values (‘NJX0001′,’NLU9999′,’Goiás’)

Insert Into FaixasDePlacasPorEstado Values (‘NLV0001′,’NMO9999′,’Alagoas’)

Insert Into FaixasDePlacasPorEstado Values (‘NMP0001′,’NNI9999′,’Maranhão’)

Insert Into FaixasDePlacasPorEstado Values (‘NNJ0001′,’NOH9999′,’Rio Grande do Norte’)

Insert Into FaixasDePlacasPorEstado Values (‘NOI0001′,’NPB9999′,’Amazonas’)

Insert Into FaixasDePlacasPorEstado Values (‘NPC0001′,’NPQ9999′,’Mato Grosso’)

Insert Into FaixasDePlacasPorEstado Values (‘NPR0001′,’NQK9999′,’Paraíba’)

Insert Into FaixasDePlacasPorEstado Values (‘NQL0001′,’NRE9999′,’Ceará’)

Insert Into FaixasDePlacasPorEstado Values (‘NRF0001′,’NSD9999′,’Mato Grosso do Sul’)

Insert Into FaixasDePlacasPorEstado Values (‘NSE0001′,’NTC9999′,’Pará’)

Insert Into FaixasDePlacasPorEstado Values (‘NTD0001′,’NTW9999′,’Bahia’)

Insert Into FaixasDePlacasPorEstado Values (‘NTX0001′,’NUG9999′,’Mato Grosso’)

Insert Into FaixasDePlacasPorEstado Values (‘NUH0001′,’NUL9999′,’Roraima’)

Insert Into FaixasDePlacasPorEstado Values (‘NUM0001′,’NVF9999′,’Ceará’)

Insert Into FaixasDePlacasPorEstado Values (‘NVG0001′,’NVN9999′,’Sergipe’)

Insert Into FaixasDePlacasPorEstado Values (‘NVO0001′,’NWR9999′,’Goiás’)

Insert Into FaixasDePlacasPorEstado Values (‘NWS0001′,’NXQ9999′,’Maranhão’)

Insert Into FaixasDePlacasPorEstado Values (‘NXR0001′,’NXT9999′,’Acre’)

Insert Into FaixasDePlacasPorEstado Values (‘NXU0001′,’NXW9999′,’Pernambuco’)

Insert Into FaixasDePlacasPorEstado Values (‘NXX0001′,’NYG9999′,’Minas Gerais’)

Insert Into FaixasDePlacasPorEstado Values (‘NYH0001′,’NZZ9999′,’Bahia’)

Insert Into FaixasDePlacasPorEstado Values (‘OAA0001′,’OAO9999′,’Amazonas’)

Insert Into FaixasDePlacasPorEstado Values (‘OAP0001′,’OBS9999′,’Mato Grosso’)

Insert Into FaixasDePlacasPorEstado Values (‘OBT0001′,’OCA9999′,’Pará’)

Insert Into FaixasDePlacasPorEstado Values (‘OCB0001′,’OCU9999′,’Ceará’)

Insert Into FaixasDePlacasPorEstado Values (‘OCV0001′,’ODT9999′,’Espírito Santo’)

Insert Into FaixasDePlacasPorEstado Values (‘ODU0001′,’OEI9999′,’Piauí’)

Insert Into FaixasDePlacasPorEstado Values (‘OEJ0001′,’OES9999′,’Sergipe’)

Insert Into FaixasDePlacasPorEstado Values (‘OET0001′,’OFH9999′,’Paraíba’)

Insert Into FaixasDePlacasPorEstado Values (‘OFI0001′,’OFW9999′,’Pará’)

Insert Into FaixasDePlacasPorEstado Values (‘OFX0001′,’OGG9999′,’Paraíba’)

Insert Into FaixasDePlacasPorEstado Values (‘OGH0001′,’OHA9999′,’Goiás’)

Insert Into FaixasDePlacasPorEstado Values (‘OHB0001′,’OHK9999′,’Alagoas’)

Insert Into FaixasDePlacasPorEstado Values (‘OHL0001′,’OHW9999′,’Rondônia’)

Insert Into FaixasDePlacasPorEstado Values (‘OHX0001′,’OIQ9999′,’Ceará’)

Insert Into FaixasDePlacasPorEstado Values (‘OIR0001′,’OJK9999′,’Maranhão’)

Insert Into FaixasDePlacasPorEstado Values (‘OJR0001′,’OKC9999′,’Rio Grande do Norte’)

Insert Into FaixasDePlacasPorEstado Values (‘OKI0001′,’OLG9999′,’Bahia’)

Insert Into FaixasDePlacasPorEstado Values (‘OLH0001′,’OLN9999′,’Tocantins’)

Insert Into FaixasDePlacasPorEstado Values (‘OLO0001′,’OMH9999′,’Minas Gerais’)

Insert Into FaixasDePlacasPorEstado Values (‘OMI0001′,’OOF9999′,’Goiás’)

Insert Into FaixasDePlacasPorEstado Values (‘OOG0001′,’OOU9999′,’Mato Grosso do Sul’)

Insert Into FaixasDePlacasPorEstado Values (‘OOV0001′,’ORC9999′,’Minas Gerais’)

Insert Into FaixasDePlacasPorEstado Values (‘ORD0001′,’ORM9999′,’Alagoas’)

Insert Into FaixasDePlacasPorEstado Values (‘ORN0001′,’OSV9999′,’Ceará’)

Insert Into FaixasDePlacasPorEstado Values (‘OSW0001′,’OTZ9999′,’Pará’)

Insert Into FaixasDePlacasPorEstado Values (‘OUA0001′,’OUE9999′,’Piauí’)

Insert Into FaixasDePlacasPorEstado Values (‘OUF0001′,’OVD9999′,’Bahia’)

Insert Into FaixasDePlacasPorEstado Values (‘OVE0001′,’OWC9999′,’Espírito Santo’)

Insert Into FaixasDePlacasPorEstado Values (‘OWD0001′,’OYG9999′,’Santa Catarina’)

Insert Into FaixasDePlacasPorEstado Values (‘PEE0001′,’PFQ9999′,’Pernambuco’)

Insert Into FaixasDePlacasPorEstado Values (‘PFR0001′,’PGK9999′,’Pernambuco’)

Insert Into FaixasDePlacasPorEstado Values (‘PGL0001′,’PHE9999′,’Pernambuco’)

Insert Into FaixasDePlacasPorEstado Values (‘SAV0001′,’SAV9999′,’São Paulo’)

Go

 

— Validando os dados inseridos na Tabela FaixasDePlacasPorEstado —

Select * From FaixasDePlacasPorEstado
Go

 

— Inserindo 9999 linhas de registros lógicos na Tabela Numeracao —

Insert Into Numeracao Default Values

Go 9999

 

— Validando os dados inseridos na Tabela Numeracao —

Select * From Numeracao

Go

Muito bem, agora que temos nossa estrutura quase toda montada, vamos avançar mais um pouco e fazer uso da análise combinatória, conforme o Bloco de Código 2 declarado abaixo:

 

— Bloco de Código 2 —

 

— Montando a CTE Recursiva para Gerar todas as combinações de Letras —

;With CTEMeuAlfabeto

As

(Select * From (Values (‘A’),(‘B’),(‘C’),(‘D’),(‘E’),(‘F’),(‘G’),(‘H’),(‘I’),(‘J’),(‘K’),

(‘L’),(‘M’),(‘N’),(‘O’),(‘P’),(‘Q’),(‘R’),(‘S’),(‘T’),(‘U’),(‘V’),

(‘W’),(‘X’),(‘Y’),(‘Z’)) As Alfabeto (LetrasDoAlfabeto)

)

— Inserindo as combinações de letras na Tabela LetrasCombinadas —

Insert Into LetrasCombinadas

Select Distinct Concat(A1.LetrasDoAlfabeto, A2.LetrasDoAlfabeto, A3.LetrasDoAlfabeto) As ConcatenacaoLetrasCombinadas

From CTEMeuAlfabeto A1

Cross Join CTEMeuAlfabeto A2 — Aqui que a mágia acontece —

Cross Join CTEMeuAlfabeto A3 — O cross join vai cruzar e combinar todas as letras —

Order By ConcatenacaoLetrasCombinadas Asc

Go

 

— Validando os dados inseridos na Tabela LetrasCombinadas —

Select * From LetrasCombinadas

Go

Nosso Bloco de Código 2 já deve ter sido processado, pois ele é especificamente o centro das atenções para conseguirmos criar todas as combinações possíveis de letras do nosso alfabeto, que estará criando em poucos segundos um total de: 17.756 (Dezessete Mil, Setecentos e Cinquenta e Seis) combinações de letras distintas.

Ufa, estamos avançando, você vai poder notar neste post, que estou fazendo uso de diversos comandos e técnicas existentes no SQL Server desde as primeiras versões como também outros implementados nas versões mais atuais, dentre eles destaco o uso de Tabela Derivada conforme o comando Select From (Values()) existente desde a versão 2000, e também da CTE – Common Table Expression adicionado ao Microsoft SQL Server a partir da versão 2005.

Vamos avançar mais ainda, pois o objetivo deste post não é mostrar somente o uso da análise combinatória, ao contrário, o estudo aqui criado, me permitiu elaborar alguns cenários que me permitiram adotar formas e técnicas diferentes de realizar todas as combinações entre letras e números afim de processar, criar e armazenar todas as placas criadas justamente na tabela denominada placas.

Destaco que foram criados 3 (três) cenários de estudo de acordo com percepções e análises que realizei, fazendo uso de recursos e técnicas distintas visando identificar o que poderia ser melhor utilizada:

  • Cenário 1 – Inserindo dados na Tabela de Placas através de Loop Condicional;
  • Cenário 2 – Inserindo dados na Tabela de Placas através de CTE Recursiva com Junção Cruzada; e
  • Cenário 3 – Inserindo dados na Tabela de Placas através de Junção Cruzada.

Nota: Tenho a certeza que você vai poder criar outros cenários e novas análises, como também, utilizar os mais variados recursos e funcionalidades existentes no Microsoft SQL Server, reforço mais uma vez que estes cenários são meras amostras de estudo e comparações do meu entendimento.

O objetivo de ter criado estes cenários, possibilitou realizarmos comparações de tempo de processamento no que relaciona ao uso da CPU e consumo de memória RAM para cada um dos cenários.

A Tabela 1 declarada abaixo apresenta um resumo dos valores obtidos durante 5 rodadas de processamento executadas em meu ambiente:

Cenário

Média de Uso de CPU Média do Uso de Memória em GBs Média de Uso de Disco Rígido Tempo Mínimo de processamento

Tempo Máximo de processamento

01 57% 3.5 Gbs 65% 19 Hrs e 23 segundos 21Hrs e 18 segundos
02 34% 2.8 Gbs 42% 33 minutos e 6 segundos 42 minutos e 27 segundos
03 18% 2.0 Gbs 24% 6 minutos e 13 segundos 10 minutos e 25 segundos

Tabela 1 – Resumo comparativo do uso de CPU, Memória e Disco, em conjunto com os tempos de processamento demandados para cada cenário.

Show, agora que temos este pequeno resumo dos tempos de processamento e uso dos principais recursos de hardware, já podemos conhecer cada um dos cenários elaborados abaixo, conforme apresenta o Bloco de Código 3 a seguir:

— Bloco de Código 3 —

 

— Cenário 1 –

 

— Inserindo dados na Tabela de Placas através de Loop Condicional – 19Hrs e 33s de processamento —

 

— Limpando a Tabela de Placas —

Truncate Table Placas

Go

 

— Declarando as variáveis de controle —

Declare @ContadorSequencialTotalPlacasInseridas Int = 1,

@ContadorSequencialParcialPlacasInseridas Int = 1,

@CodigoSequencialLetrasCombinadas Int = 1

 

— Abrindo o Loop de Inserção —

While @ContadorSequencialTotalPlacasInseridas <=(Select Max(CodigoSequencialLetrasCombinadas) From LetrasCombinadas)

Begin

 

Set @CodigoSequencialLetrasCombinadas=(Select CodigoSequencialLetrasCombinadas From LetrasCombinadas

Where CodigoSequencialLetrasCombinadas = @ContadorSequencialTotalPlacasInseridas)

 

While @ContadorSequencialParcialPlacasInseridas <=9999 — Contador a cada 9999 incrementa a variável @ContadorSequencialTotalPlacasInseridas

Begin

Insert Into Placas (CodigoSequencialLetrasCombinadas, CodigoSequencialNumeroPlacas)

Values (@CodigoSequencialLetrasCombinadas, @ContadorSequencialParcialPlacasInseridas)

Set @ContadorSequencialParcialPlacasInseridas         +=1

End

 

Set @ContadorSequencialParcialPlacasInseridas = 1

Set @CodigoSequencialLetrasCombinadas +=1

Set @ContadorSequencialTotalPlacasInseridas +=1

 

End

 

— Cenário 2 –

 

— Inserindo dados na Tabela de Placas através de CTE Recursiva com Junção Cruzada — 33 minutos e 40s de processamento —

 

— Limpando a Tabela de Placas —

Truncate Table Placas

Go

 

— Declarando as variáveis de controle —

Declare @ContadorSequencialTotalPlacasInseridas Int = 1,

@CodigoSequencialLetrasCombinadas SmallInt = 1

 

While @ContadorSequencialTotalPlacasInseridas <=(Select Max(CodigoSequencialLetrasCombinadas) From LetrasCombinadas)

Begin

 

— Realizando a Junção Cruzada entre as Tabelas LetrasCombinadas x CTENumeracao —

;With CTENumeracao

As

(Select 1 As Numero

Union All

Select Numero + 1 From CTENumeracao

Where Numero <=9998

)

Insert Into Placas (CodigoSequencialLetrasCombinadas, CodigoSequencialNumeroPlacas)

Select LC.CodigoSequencialLetrasCombinadas, N.Numero

From LetrasCombinadas LC Cross Join — Aqui acontece a mágia

CTENumeracao N — Cross Joi vai combinar todas as Letras com 9999 números —

Where CodigoSequencialLetrasCombinadas = @CodigoSequencialLetrasCombinadas

Option (MaxRecursion 0)

 

Set @CodigoSequencialLetrasCombinadas +=1

Set @ContadorSequencialTotalPlacasInseridas +=1

End

Go

 

— Cenário 3 –

 

— Inserindo dados na Tabela de Placas através de Junção Cruzada – 10 minutos e 27s de processamento —

 

— Limpando a Tabela de Placas —

Truncate Table Placas

Go

 

— Declarando as variáveis de controle —

Declare @ContadorSequencialTotalPlacasInseridas Int = 1,

@CodigoSequencialLetrasCombinadas SmallInt = 1

 

While @ContadorSequencialTotalPlacasInseridas <=(Select Max(CodigoSequencialLetrasCombinadas) From LetrasCombinadas)

Begin

 

— Realizando a Junção Cruzada entre as Tabelas LetrasCombinadas x Numeracao —

Insert Into Placas (CodigoSequencialLetrasCombinadas, CodigoSequencialNumeroPlacas)

Select LC.CodigoSequencialLetrasCombinadas, N.CodigoNumeracao

From LetrasCombinadas LC Cross Join — Aqui acontece a mágia

Numeracao N — Cross Joi vai combinar todas as Letras com 9999 números —

Where CodigoSequencialLetrasCombinadas = @CodigoSequencialLetrasCombinadas

 

Set @CodigoSequencialLetrasCombinadas +=1

Set @ContadorSequencialTotalPlacasInseridas +=1

End

Go

 

Show, show, e show, nossos três cenários de estudo e testes já estão apresentados, basta você escolher qual deseja brincar, executar, encontrar as melhorias e possíveis falhas que podem existir.

Pra finalizar nossa longa caminhada, apresento o Bloco de Código 4, o qual vai ilustrar como podemos consultar nossas tabelas e obter os dados já inseridos após o processamento de um dos cenários, e por fim o Bloco de Código 5 que apresenta o código utilizado no Bloco de Código 4 transformado em uma Stored Procedure denominada: P_PesquisarPlacas.

— Bloco de Código 4 —

— Apresentando as 100 primeiras Placas Geradas —

Select Top 100 Concat(LC.SequencialDeLetrasCombinadas,’-‘,

Convert(Char(4),Case

When P.CodigoSequencialNumeroPlacas BetWeen 1 And 9 Then Concat(‘000’,P.CodigoSequencialNumeroPlacas)

When P.CodigoSequencialNumeroPlacas BetWeen 10 And 99 Then Concat(’00’,P.CodigoSequencialNumeroPlacas)

When P.CodigoSequencialNumeroPlacas BetWeen 100 And 999 Then Concat(‘0’,P.CodigoSequencialNumeroPlacas)

When P.CodigoSequencialNumeroPlacas BetWeen 1000 And 9999 Then Convert(Char(4),P.CodigoSequencialNumeroPlacas)

End)) As ‘Placa’,

IsNull(F.FaixasDePlacasPorEstadoNomeDoEstado,’Sequência não atribuída…’) As ‘Nome do Estado’

From LetrasCombinadas LC Inner Join Placas P

On LC.CodigoSequencialLetrasCombinadas = P.CodigoSequencialLetrasCombinadas

Left Join FaixasDePlacasPorEstado F

On LC.SequencialDeLetrasCombinadas Between SubString(F.CodigoSequencialFaixasDeLetrasNumerosInicial,1,3)

And SubString(F.CodigoSequencialFaixasDeLetrasNumerosFinal,1,3)

Go

A Figura 1 apresentada abaixo, ilustra o possível resultado obtido após a execução do Bloco de Código 4:

Figura 1 – Relação das 100 primeiras placas de carros criadas e inseridas na tabela Placas.

— Bloco de Código 5 —

 

— Criando uma Stored Procedure para pesquisa de placas —

Create or Alter Procedure P_PesquisarPlacas @LetrasCombinadas Char(3), @SequenciaNumerica SmallInt = Null

As

Begin

 

Set NoCount On

 

Select Concat(LC.SequencialDeLetrasCombinadas,’-‘,

Convert(Char(4),Case

When P.CodigoSequencialNumeroPlacas BetWeen 1 And 9 Then Concat(‘000′,P.CodigoSequencialNumeroPlacas)

When P.CodigoSequencialNumeroPlacas BetWeen 10 And 99 Then Concat(’00’,P.CodigoSequencialNumeroPlacas)

When P.CodigoSequencialNumeroPlacas BetWeen 100 And 999 Then Concat(‘0’,P.CodigoSequencialNumeroPlacas)

When P.CodigoSequencialNumeroPlacas BetWeen 1000 And 9999 Then Convert(Char(4),P.CodigoSequencialNumeroPlacas)

End)) As ‘Placa’,

IsNull(F.FaixasDePlacasPorEstadoNomeDoEstado,’Sequência não atribuída…’) As ‘Nome do Estado’

From LetrasCombinadas LC Inner Join Placas P

On LC.CodigoSequencialLetrasCombinadas = P.CodigoSequencialLetrasCombinadas

Left Join FaixasDePlacasPorEstado F

On LC.SequencialDeLetrasCombinadas Between SubString(F.CodigoSequencialFaixasDeLetrasNumerosInicial,1,3)

And SubString(F.CodigoSequencialFaixasDeLetrasNumerosFinal,1,3)

Where LC.SequencialDeLetrasCombinadas = @LetrasCombinadas

And P.CodigoSequencialNumeroPlacas = @SequenciaNumerica

End

Após a Stored Procedure estar criada, basta realizar sua execução conforme o exemplo apresentado abaixo, passando a sequência de letras e números que você deseja consultar.

Importante: Destaco que algumas combinações de placas de carro ainda não estão sendo utilizadas em nosso território, dentre elas as que começam com as letras: W, X, Y e Z.

 

— Executando a Stored Procedure P_PesquisarPlacas —

Exec P_PesquisarPlacas ‘FBD’,3127

Go

Sensacional, chegamos ao final, missão cumprida e entregue, acredito que este foi um dos estudos mais prazerosos e de grande obtenção de conhecimento que eu realizei nos últimos meses.

Antes de encerrarmos, gostaria de contar com a sua participação neste post, respondendo a enquete abaixo:

 

REFERÊNCIAS

https://www.infoescola.com/matematica/analise-combinatoria/

https://mundoeducacao.bol.uol.com.br/matematica/analise-combinatoria.htm

https://docs.microsoft.com/en-us/sql/t-sql/queries/from-transact-sql

https://docs.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql

https://www.mssqltips.com/sqlservertip/1042/using-derived-tables-to-simplify-the-sql-server-query-process/

https://docs.microsoft.com/pt-br/sql/t-sql/language-elements/select-local-variable-transact-sql

 

Posts Anteriores

 

CONCLUSÃO

Como de costume, tenho um imenso prazer em poder compartilhar um pouco das minhas experiências, estudos e conhecimentos que estou diariamente formando sobre este fantástico Sistema Gerenciador de Banco de Dados chamado Microsoft SQL Server.

Hoje não seria diferente, mais uma vez você pode notar o quanto ele é capaz de nos surpreender com sua inteligência, sabedoria, e principalmente sua capacidade de conseguir aplicar as mais variadas técnicas existentes da Matemática para solucionar algo que pode parecer tão complexo para o raciocínio humano.

Neste post, utilizei algumas das mais variadas técnicas para se trabalhar com combinações de dados, utilização de dados em memória através de um Select From (Values()), em conjunto com tabelas criadas fisicamente ou tabelas declaradas como expressões em um CTE.

Por fim, fizemos usado mais uma vez da Matemática aplicando a análise condicional em conjunto com seus elementos de permutação e arranjo de valores.

Através dos cenários apresentados, em conjunto com a gama de recursos que ele nos permite utilizar, conseguimos aplicar as mais variadas preposições de análises de dados que nos possibilita identificar qual cenário pode ser a melhor maneira de se tomar uma decisão.

Este é o fantástico Microsoft SQL Server, produto tão fascinante que a cada dia eu não consigo deixar de querer estudar e conhecer mais ainda.

 

Agradecimentos

Agradeço a você por sua atenção e visita ao meu blog. Fique à vontade para enviar suas críticas, sugestões, observações e comentários.

Nos encontramos no próximo post da sessão Dica do Mês a ser publicado em breve.

Um forte abraço, curta esta nova estação do ano que começou a alguns dias atrás, eu adoro o outono.

Até mais.

Dica do Mês – Temporal Table e o Calor, uma combinação muito quente


Salve pessoal, bom dia.

Estamos no mês de janeiro, férias, sol, calor, chuvas, e para minha alegria te encontro mais uma vez no meu blog, caso esta seja a sua primeira visita ou acesso, fico mais feliz ainda, seja muito bem vindo.

Este é mais um post da sessão Dica do Mês, sessão dedicada a compartilhar bimestralmente dicas, novidades, curiosidades e demais assuntos, conteúdos e informações relacionadas ao Microsoft SQL Server, Banco de Dados e Tecnologias de Banco de Dados.

No post de hoje, quero compartilhar com vocês uma das funcionalidades adicionadas ao Microsoft SQL Server a partir da versão 2016 e que recentemente acabei conhecendo com um pouco mais, como você já pode notar no título deste post, estou fazendo referência as chamadas Temporal Tables (Tabelas Temporais).

Você já conhece? Teve a necessidade de utilizar? Eu particularmente falando conhecia muito pouco sobre este recurso, mas na semana passada neste período de férias tive a ideia de fazer uma brincadeira aqui em casa em conjunto com um termômetro, e justamente através desta brincadeira que utilizei uma temporal table.

Ficou curioso para saber como eu fiz uso dela? Calma, daqui a pouco eu conto mais sobre isso para você.

Pois bem, sem mais delongas, vamos em frente, vou tentar mitigar a sua curiosidade e ao mesmo também satisfazer os meus objetivos. Sendo assim, seja bem vindo ao post – Dica do Mês – Temporal Table e o Calor, uma combinação muito quente.


Introdução

A partir da versão 2016 do Microsoft SQL Server, a Microsoft introduziu o suporte para tabelas temporais de sistema baseadas no versionamento de dados como um recurso de banco de dados, sendo este,  uma funcionalidade que traz o suporte interno para fornecer informações sobre dados armazenados na tabela em qualquer ponto no tempo, ao invés de apenas os dados que é corretos no momento atual em está na hora.

Esta nova funcionalidade, também é reconhecida e trata como um recurso de banco de dados criado com base nos padrões em ANSI SQL 2011.

A partir do momento em que idealizamos fazer uso de uma tabela temporal, estamos criando um novo objeto ou transformando um objeto já existente em nosso banco de dados, em um elemento responsável em manter o histórico completo das alterações de dados ocorridos durante um período de tempo, sendo esta a principal finalidade de uso de uma temporal que é tratada internamento como um repositório de gerenciamento de tempo.

Cada tabela temporal tem duas colunas explicitamente definidas, cada um com um tipo de dados datetime2 , estas colunas são referidas como colunas de período, sendo período colunas usadas exclusivamente pelo sistema de registro prazo de validade para cada linha, sempre que uma linha for modificada. Além dessas colunas de período, uma tabela temporal também contém uma referência a outra tabela, a qual será utilizada como esquema espelho.

Por padrão o Microsoft SQL Server utiliza esta tabela para armazenar automaticamente a versão anterior de uma linha cada vez que a mesma na tabela temporal é atualizada ou excluída. Esta tabela adicional é referida como a tabela de histórico, enquanto a tabela principal que armazena versões de linha (real) atual é conhecida como a tabela atual ou simplesmente como a tabela temporal.

Importante ressaltar que durante a criação do quadro temporal, os usuários podem especificar a existência de uma tabela de histórico (deve ser esquema compatível) ou deixar o sistema criar tabela de histórico padrão.

Agora que já conhecemos um pouco do que é uma Temporal Table, vamos avançar mais um pouco em nossa caminhada, vou apresentar o porque tive a ideia de fazer uso deste recurso.

 

SEU FUNCIONAMENTO

Como já destacado anteriormente o sistema de controle de versão de uma tabela temporal é implementado através do uso de um par de tabelas, uma tabela atual e uma tabela de histórico. Dentro de cada uma destas tabelas, as seguintes duas colunas adicionais datetime2 são usadas para definir o período de validade para cada linha:

  • Coluna de início de período: O sistema registra a hora de início para a linha nesta coluna, denotado tipicamente como a coluna de SysStartTime .
  • Coluna de fim do período: O sistema registra a hora final para a linha nesta coluna, normalmente indicado na coluna SysEndTime .

A tabela atual contém o valor atual para cada linha. A tabela de histórico contém cada valor anterior para cada linha, se for o caso, e a hora de início e hora de término para o período para o qual foi válido.

A Figura 1 apresentada abaixo, ilustra de forma simples o funcionamento do sistema de controle dos dados aplicado a partir do uso de uma tabela temporal:

Temporal-HowWorks

Figura 1 – Funcionamento do sistema de controle de uma tabela temporal.

Este sistema de controle de versionamento dos dados é realizado sempre as instruções: Insert, Update, Delete ou Merge venham a ser realizadas de forma individual ou simultânea.

 

PORQUE UTILIZAR UMA TEMPORAL TABLE

Uma das coisas que eu aprendi a gostar no decorrer da minha carreira na área de tecnologia é a importância e as possibilidades de mudanças que um mesmo dado pode apresentar no decorrer de um período de tempo, este é um dos meus maiores prazeres entender o quanto aquele dado a uma minuto atrás agora já é outro dado e podem me trazer representar novas informações e conhecimentos.

Desta forma, ao analisarmos uma temporal table podemos também reconhecer ou fazer uso da mesma como uma Slowly Changing Dimension (Dimensão com mudanças lentas ou mudanças lentas em uma dimensão), o que vai nos possibilitar criar uma visão dos nossos dados com base uma período ou determinada data.

Uma outra funcionalidade que pode ser aplicada a uma temporal table se relacionada a controles de auditoria mais propriamente falando de auditoria de dados, normalmente as fontes de dados reais são dinâmicas e se tornam voláteis ao longo do tempo, para uma empresas isso pode influenciar diretamente em suas decisões as quais dependem de percepções que os analistas podem começar a identificar a partir da evolução ou mudanças de dados.

Já sabemos o porque escolhi fazer uso de uma temporal table, agora vou apresentar o cenário que me permitiu aplicar este recurso com base na minha ideia.

 

MINHA IDEIA

Estamos visando uma forte onda de calor em praticamente todo o Brasil, algo que muitos brasileiros adoram eu sinceramente não sou um destes brasileiros, pois eu não suporto estas altas temperaturas.

Para tentar de alguma maneira aprender algo de novo com este calor e tentando se distrair dentro das possibilidades, pensei em ter uma noção do quanto a temperatura aqui na minha casa localizada na cidade de São Roque interior do estado de São Paulo muda no decorrer de um período de tempo, sendo justamente esta a minha ideia de utilizar uma temporal table, talvez esta não tenha sido a melhor ideia ou até mesmo o melhor cenário para uso, mas entendo que pode ser uma possibilidade dentre as mais variadas possíveis.

Seguindo em frente e avançando mais um pouco, chegou a hora de colocar em prática a minha ideia, para isso vamos construir um simples cenário para fazer uso da Temporal Table.

NOSSO AMBIENTE

Como de costume vamos utilizar um ambiente isolado dos demais bancos de dados que você possa conter, desta maneira nosso cenário será constituído dos seguintes elementos:

  • Banco de Dados: DatabaseTemporalTabel;
  • Tabela Atual: TemporalTableTemperatura;
  • Tabela Historico: TemporalTableTemperaturaHistorico;
  • Colunas Temporais: DataHoraInicial e DataHoraFinal; e
  • Period For System formado por: DataHoraInicial e DataHoraFinal.

Criando o ambiente

Através do Bloco de Código 1 apresentado abaixo, vamos realizar a criação dos respectivos elementos destacados anteriormente:

— Bloco de Código 1 —

— Criando o Banco de Dados —
Create Database DatabaseTemporalTable
Go

— Acessando o Banco de Dados —
Use DatabaseTemporalTable
Go

— Criando a Tabela TemporalTableTemperatura —
Create Table TemporalTableTemperatura
(Codigo Int Identity(1,1) Primary Key Clustered,
Local Char(10) Default ‘Minha Casa’,
Cidade Char(9) Default ‘São Roque’,
DataAtual Date Default GetDate(),
HoraAtual Time Default GetDate(),
Temperatura TinyInt,
DataHoraInicial Datetime2 (0) GENERATED ALWAYS AS ROW START,
DataHoraFinal Datetime2 (0) GENERATED ALWAYS AS ROW END,
PERIOD FOR SYSTEM_TIME (DataHoraInicial, DataHoraFinal))
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.TemporalTableTemperaturaHistorico))
Go

A Figura 2 apresentada abaixo, ilustra a estrutura da tabela TemporalTableTemperatura e sua tabela espelho TemporalTableTemperaturaHistorico:

Figura 2 – Tabelas TemporalTableTemperatura e TemporalTableTemperaturaHistorico.

Observações

1 – Para que o Microsoft SQL Server reconheça uma tabela como Temporal Table as colunas temporais devem ser formadas pelo tipo de dados DateTime2 e logo após a declaração do seu tipo de dados informar as instruções:

  • Generated Always as Row Start – Valor gerado sempre no início da linha; e
  • Generated Always as Row End – Valor gerado sempre no final da linha.

2 – O controle do período dos valores é feito através da instrução PERIOD FOR SYSTEM_TIME, declarada obrigatoriamente no final da construção da tabela, formada pelas colunas que recebem os valores DateTime2.

3 – Ao declarar o nome da tabela a ser utilizada para o versionamento dos dados, é obrigatório informar o nome do ower ou schema a qual esta tabela irá pertencer, caso isso não seja feito o Microsoft SQL Server retornará a seguinte mensagem de erro:

Msg 13539, Level 15, State 1, Line 18
Setting SYSTEM_VERSIONING to ON failed because history table ‘TemporalTableTemperaturaHistorico2 is not specified in two-part name format.

4 – Ao informar a tabela que será utilizada para o versionamento dos dados o Database Engine realiza automaticamente a criação desta tabela histórico caso a mesma não exista.

Ótimo estamos no caminho certo, nosso próximo passo será abastecer a tabela TemporalTableTemperatura com dados iniciais e na sequência proporcionar alterações nestes mesmos dados iniciais para que o Database Engine faça uso da nossa Temporal Table registrando na Tabela TemperalTableTemperaturaHistorico todas as manipulações realizadas.

Para isso vamos utilizar o Bloco de Código 2 declarado abaixo:

— Bloco de Código 2 —

— Inserindo Dados na Tabela TemporalTableTemperatura —
Insert Into TemporalTableTemperatura (Temperatura)
Values (25)
Go

— Gerando um Delay de 20 segundos —
WAITFOR DELAY ’00:00:20′
Go

— Atualizando os dados na Tabela TemporalTableTemperatura —
Update TemporalTableTemperatura
Set Temperatura = 26,
HoraAtual = GetDate()
Go

— Gerando um novo Delay de 40 segundos —
WAITFOR DELAY ’00:00:40′
Go

— Atualizando os dados na Tabela TemporalTableTemperatura —
Update TemporalTableTemperatura
Set Temperatura = 27,
HoraAtual = GetDate()
Go

— Gerando um novo Delay de 1 minuto e 20 segundos —
WAITFOR DELAY ’00:01:20′
Go

— Atualizando os dados na Tabela TemporalTableTemperatura —
Update TemporalTableTemperatura
Set Temperatura = 27,
HoraAtual = GetDate()
Go

Até aqui tudo tranquilo, realizamos o processo de inserção de dados iniciais na tabela TemporalTableTemperatura e na sequência através do comando WaitFor forçamos a ocorrência de alguns delays (atrasos) de tempo para simular o aumento da temperatura como se fosse um termômetro realizando uma nova marcação, com isso, já temos neste momento um pequena porção de dados a serem consultados.

Vamos então executar o Bloco de Código 3 a seguir para identificar as possíveis maneiras de se consultar os dados armazenados em nossa temporal table:

— Bloco de Código 3 —

— Consultando dados na Tabela TemporalTableTemperatura —
Select * From TemporalTableTemperatura
Go

Após realizarmos o Select declarado acima teremos um retorno de dados similar ao apresentado na Figura 3 abaixo:
Figura 3 – Posição atual de dados armazenados na tabela TemporalTableTemperatura.

Observe que a coluna Temperatura apresenta o valor 27, número informado no último update realizado, a coluna DataHoraInicial apresentando o valor que representa o início da realização da última manipulação aplicada a tabela, no caso o comando Update e a coluna DataHoraFinal vai apresentar o valor final que representa o encerramento do período de controle de versionamento dos dados com o valor fixo e padrão 9999-12-31 23:59:59.

Pois bem, mas se quisermos então identificar ao longo do tempo todas as manipulação que podem ter ocorrido em nossa tabela temporal? É ai que entra em ação nossa tabela de espelho, nossa tabela TemporalTableTemperaturaHistorico, a qual é responsável em armazenar e controlar todo versionamento e alterações que venham a ser realizadas em nossa Temporal Table.

O próximo passo consiste na execução do Bloco de Código 4, o qual vai nos permitir consumir os dados temporais armazenados em nossa tabela TemporalTableTemperaturaHistorico:

— Bloco de Código 4 —

— Consultando dados Temporais, obtendo todas as manipulações realizadas —
Select * From TemporalTableTemperatura
For System_Time All — Apresenta todas as manipulações realizadas
Go

Figura 4 – Todas as manipulações realizadas na tabela TemporalTableTemperatura armazenadas de forma espealhada na tabela histórico TemporalTableTemperaturaHistorico.

Nota que a coluna DataHoraFinal apresenta na linha 1 o valor fixo e padrão 9999-12-31 23:59:59, mas no decorrer das demais linhas, de acordo com as operações realizadas os valores foram sendo atualizados, como podemos comprovar na linha 7 a qual apresenta o valor 2019-01-22 12:59:42.

Já estamos praticamente no final desta caminhada, nosso últimos passos consistem em realizar outras formas de consultar dados temporais, através das instruções:

  • For System_Time as Of;
  • For System_Time From ” To ”;
  • For System_Time Between ” And ”; e
  • For System_Time Contained In ().

Para realizar estas consultamos, vamos executar o Bloco de Código 5 apresentando abaixo:

— Bloco de Código 5 —

— Conhecendo outras formas de consultar dados temporais —
Select * From TemporalTableTemperatura
For System_Time as Of ‘2019-01-22 12:33:56’
Go

Select * From TemporalTableTemperatura
For System_Time From ‘2019-01-22 12:33:56’ To ‘2019-01-22 12:48:36’
Go

Select * From TemporalTableTemperatura
For System_Time Between ‘2019-01-22 12:48:36’ And ‘2019-01-22 12:58:22’
Order By Temperatura Desc
Go

Select * From TemporalTableTemperatura
For System_Time Contained In (‘2019-01-22 12:33:00′ ,’2019-01-22 12:55:00’)
Go

A Figura 5 a seguir apresentado o resultado tornado após a execução do Bloco de Código 5 declarado acima:Figura 5 – Resultados obtidos após a execução de cada comando select declarado no Bloco de Código 5.

Praticamente términos, mas quero finalizar este post com uma pequena amostra do quanto uma tabela temporal pode ser útil, imagine se excluirmos todos os dados da nossa tabela TemporalTableTemperatura.

O que aconteceria com os dados em nossa tabela espelho:

1 – Os dados seriam excluídos também?

2 – Os dados são mantidos?

3 – A tabela espelho será excluída?

4 – Não podemos remover dados em tabelas que utilizam versionamento de dados?

Bom, vou deixar o Bloco de Código 6 declarado abaixo, mas a respostas para esta pergunta você que vai descobrir e posteriormente publicar seu comentário aqui neste post:

— Bloco de Código 6 —

— Excluíndo os dados cadastrados na Tabela TemporalTableTemperatura —
Delete From TemporalTableTemperatura
Go

— Consultando dados na Tabela TemporalTableTemperaturaHistorico —
Select Local, Cidade, DataAtual, HoraAtual, Temperatura
From TemporalTableTemperaturaHistorico
Go

Com isso chegamos ao final de mais um post da sessão Dica do Mês, antes de encerrarmos, gostaria de contar com a sua participação neste post, respondendo a enquete abaixo:


Referências

https://docs.microsoft.com/en-us/sql/relational-databases/tables/temporal-tables?view=sql-server-2017

https://en.wikipedia.org/wiki/Slowly_changing_dimension

https://docs.microsoft.com/en-us/sql/relational-databases/tables/creating-a-system-versioned-temporal-table?view=sql-server-2017

https://social.technet.microsoft.com/wiki/pt-br/contents/articles/12580.slowly-changing-dimensions.aspx

https://docs.microsoft.com/en-us/sql/relational-databases/tables/querying-data-in-a-system-versioned-temporal-table?view=sql-server-2017

https://docs.microsoft.com/en-us/sql/relational-databases/tables/getting-started-with-system-versioned-temporal-tables?view=sql-server-2017

https://docs.microsoft.com/en-us/sql/relational-databases/tables/system-versioned-temporal-tables-with-memory-optimized-tables?view=sql-server-2017

https://docs.microsoft.com/en-us/sql/relational-databases/tables/temporal-table-metadata-views-and-functions?view=sql-server-2017

https://docs.microsoft.com/en-us/sql/t-sql/language-elements/waitfor-transact-sql?view=sql-server-2017

Posts Anteriores

https://pedrogalvaojunior.wordpress.com/2018/10/23/dica-do-mes-comando-restore-database-page-restaurando-paginas-de-dados-de-uma-tabela-no-microsoft-sql-server/

https://pedrogalvaojunior.wordpress.com/2018/07/26/dica-do-mes-ocultando-uma-instancia-em-execucao-do-microsoft-sql-server/

https://pedrogalvaojunior.wordpress.com/2018/04/25/dica-do-mes-sql-operations-studio-view-as-chart/

https://pedrogalvaojunior.wordpress.com/2018/03/14/dica-do-mes-microsoft-sql-server-2017-sql-graph-databases/

https://pedrogalvaojunior.wordpress.com/2018/01/24/dicadomes-sqlservertoolsuiteintroduction/

CONCLUSÃO

Como já destaquei em outros posts, a cada nova versão, atualização e correção a Microsoft transforma o SQL Server em um produto surpreende, ainda mais na sua capacidade e versatilidade de permitir aos profissionais de tecnologia, administradores de bancos de dados, programadores, entre outros, utilizar recursos nativos e também novos como ferramentas que podem nos ajudar a aplicar os mais variados possíveis cenários afim de obter soluções rápidas e práticas para nossas necessidades.

No post de hoje, mais uma vez isto foi constatado, o uso de novos recursos com base em funcionalidades já existentes se tornam ferramentas valiosas e de grande importância, podemos fazer esta relação com as tabelas temporais, funcionalidade que nos possibilita viajar, navegar, caminhar ao longo do tempo analisar e entendendo as mudanças ocorridas em nossos dados.

Desta forma, nos deparamos com uma poderosa ferramenta e sua gama de recursos que nos permitem realizar as mais diversas e variados preposições de análises de dados para identificarmos a melhor forma para se tomar uma decisão.

Este é o fantástico Microsoft SQL Server, produto tão fascinante que a cada dia eu não consigo deixar de querer estudar e conhecer mais ainda.

Agradecimentos

Agradeço a você por sua atenção e visita ao meu blog. Fique a vontade para enviar suas críticas, sugestões, observações e comentários.

Nos encontramos no próximo post da sessão Dica do Mês a ser publicado em breve.

Um forte abraço, sucesso, não se esqueça de se manter hidratado, passar bastante protetor solar para se proteger deste forte calor que estamos vivendo.

Até mais.

Dica do Mês – Comando Restore Database Page – Restaurando páginas de dados de uma tabela no Microsoft SQL Server


Olá boa tarde, que surpresa te encontrar mais uma vez no meu blog, caso esta seja a sua primeira vez, fico mais feliz ainda, seja muito bem vindo.

Este é mais um post da sessão Dica do Mês, sessão dedicada a compartilhar bimestralmente dicas, novidades, curiosidades e demais assuntos, conteúdos e informações relacionadas ao Microsoft SQL Server, Banco de Dados e Tecnologias de Banco de Dados.

No post de hoje, quero compartilhar com vocês uma das funcionalidades adicionadas ao Microsoft SQL Server a partir da versão 2016 e que recentemente acabei conhecendo com um pouco mais. 

Funcionalidade que trouxe um grande salto de qualidade ao produto, ainda mais se levarmos em consideração sua praticidade e simplicidade de uso.

Como você já pode notar no título deste post, estou me referindo a nova capacidade de recuperação de dados através do comando Restore Database em conjunto com a opção Page.

Pois bem, sem mais delongas, vamos em frente, vou tentar mitigar a sua curiosidade e ao mesmo também satisfazer os meus objetivos. Sendo assim, seja bem vindo ao post – Dica do Mês – Comando Restore Database Page – Restaurando páginas de dados de uma tabela no Microsoft SQL Server.


Introdução

Umas das tarefas mais ingratas para qualquer profissional de tecnologia, principalmente aqueles que estão diretamente relacionadas as tarefas de administração, retenção e armazenamento de dados se relaciona ao momento em que nossos ambientes começam apresentam comportamentos fora do comum ou até mesmo instabilidades. 

Quem nunca se deparou com este tipo de situação! Eu por diversas vezes passei por isso nesta minha longa estrada da vida na área de tecnologia da informação.

Mas não somente isso é importante, algo muito maior e mais preocupante podemos enfrentar, o tão temido momento de restauração de um banco de dados o chamado Restore Database, imagina então você ter que recuperar uma parte específica de uma tabela ou índice que de uma hora para outra começou a apresentar falhas e simplesmente tornou-se inacessível.

Foi justamente com base neste tipo de cenário, que o time de engenheiros da Microsoft dedicados no desenvolvimento do Microsoft SQL Server adicionaram no comando Restore Database e também no interface gráfica do Management Studio a capacidade de verificar a integridade física e lógica de uma ou mais páginas de dados, como também, a possibilidade de realizar sua restauração.

Até aqui tranquilo, nada de novidade, vamos então seguir em frente e conhecer a opção Page existente no comando Restore Database.

Tabelas e Índices

As tabelas são o coração do Microsoft SQL Server e do modelo relacional em geral, pois é onde o dado é armazenado. Cada instância de um dado na tabela representa uma entidade simples ou registro (formalmente chamado de tupla). A maioria das tabelas serão relacionadas entre si. Por exemplo: A tabela Clientes possuí um identificador único CodigoCliente que é usado como chave estrangeira no relacionamento com a tabela Pedido.

As tabelas devem ser modeladas de acordo com a teoria de banco de dados relacionais, respeitando as formas normais.

Ao criarmos nossas tabelas e índices, estamos criando internamente estrutura responsáveis em armazenar em tempo real nossos dados em áreas físicas das unidades de armazenamento de dados.

Não vou me aprofundar nos conceitos relacionados a páginas de dados, pois este não é objetivo deste post, mas sim de destacar como a Restore Database Page é importante, sua finalidade e forma de uso.

Restore Database Page

Seu objetivo é possibilitar a restauração de uma página de dados danificada sem restaurar todo o banco de dados, muito menos provocar qualquer tipo de impacto ou instabilidade no acesso aos dados após sua resturaçao.

Normalmente, as páginas que são candidatos para restauração foram marcadas como “suspeita” devido a um erro que é encontrado ao acessar a página.

As páginas suspeitas são identificadas na tabela suspect_pages no banco de dados msdb.  

Avançando mais um pouco, neste momento, já temos uma noção dos elementos básicos: Tabelas e Índices, sabemos também da estrutura que as compõem chamada de páginas de dados e de que forma estas estruturas são controladas e gerenciadas, agora vamos construir nosso cenário de testes que justamente vai nos permitir ter a visão completa de toda esta estrutura e como poderemos realizar os procedimentos de sobrescrever uma página de dados e posteriormente realizar sua restauração.

Nosso ambiente

Como de costume vamos utilizar um ambiente isolado dos demais bancos de dados que você possa conter, desta maneira nosso cenário será constituído dos seguintes elementos:

  • Banco de Dados:  RestoreDatabasePage;
  • Database Recovery Model: Full;
  • Database Page_Verify: CheckSum;
  • Tabela: TabelaCorrompida; e
  • Índice Clusterizado: Ind_TabelaCorrompida_Codigo. 

Criando o ambiente

Através do Bloco de Código 1 apresentado abaixo, vamos realizar a criação dos respectivos elementos destacados anteriormente:

— Bloco de Código 1 – Criação do Ambiente —

— Criando o Banco de Dados —
Create Database RestoreDatabasePage
Go

— Acessando —
Use RestoreDatabasePage
Go

— Criando a TabelaCorrompida —
Create Table TabelaCorrompida
(Codigo Int Identity(0,2),
ValorGUID UniqueIdentifier,
ValorRandomico BigInt,
ColunaGrande Char(100) Default ‘TC’)
Go

— Criando o Índice Clusterizado na TabelaCorrompida —
Create Clustered Index Ind_TabelaCorrompida_Codigo On TabelaCorrompida(Codigo)
Go

Como nossa estrutura base pronta, chegou a hora de popular nossa tabela realizando o processo de inserção de uma aleatória massa de dados em nossa tabela, para tal, vamos utilizar o Bloco de Código 2 apresentado a seguir:

— Bloco de Código 2 – Populando a TabelaCorrompida —
— Desabilitando a contagem de linhas processadas —
Set NoCount On
Go

— Declarando a variável de controle @Contador —
Declare @Contador Int = 0

— Abrindo bloco de transação Trans1 —
Begin Transaction Trans1

While @Contador <= 132768
Begin

Insert Into TabelaCorrompida(ValorGUID, ValorRandomico)
Values (NewId(), ABS(CHECKSUM(Rand()* 200000000)))

Set @Contador += 2
End

— Confirmando e encerrando o bloco de transação Trans1 —
Commit Transaction Trans1
Go

Observação: Note que estou fazendo uso dos comandos Begin Transaction e Commit Transaction, como forma de controle e adoção de transações explícita, sendo assim, estou informando o Microsoft SQL Server quando a transação começa e deverá ser obrigatoriamente encerrada, além disso, estou evitando e isolando o processo de inserção de dados de qualquer possibilidade de bloqueio.

Neste momento, nossa tabela já esta populada “abastecida de dados”, com um total fixo de 66385 linhas de dados, denominados tecnicamente como registros lógicos.

Vamos caminhar mais um pouco, antes de realizarmos o processo de consultar a estrutura de nossas páginas de dados e posteriormente forçar sua reescrita, vamos realizar um procedimento de backup database de nosso banco de dados, procedimento importante para garantir e possibilitar a restauração das páginas, para tal utilizaremos o Bloco de Código 3 apresentado abaixo:

— Bloco de Código 3 – Backup Database —
Backup Database RestoreDatabasePage
To Disk = ‘S:\MSSQL-2017\Backup\RestoreDatabasePage-Backup-Full.bak’  — Troque para sua                                                                                                                                              unidade de disco
With Compression,
NoFormat,
Init,
Stats=10
Go

Pronto, nosso backup já esta realizado, estamos prontos e preparados para começar a brincadeira, nosso próximo passo será obter a relação das páginas de dados que forma nossa TabelaCorrompida, para isso, vamos utilizar a não documentada function sys.fn_PhysLocFormatter, solicitando ao Microsoft SQL Server a apresentação das 100 primeiras páginas de dados da nossa tabela, conforme apresenta o Bloco de Código 4:

— Bloco de Código 4 – Obtenção a relação das páginas de dados da TabelaCorrompida —
Select TOP 100 sys.fn_PhysLocFormatter(%%physloc%%) PageId,
*
FROM TabelaCorrompida
Go

A Figura 1 apresentada a seguir ilustra o resultado obtido após a execução do Bloco de Código 4:
Figura 1 – Relação das páginas de dados e seus respectivos dados.

Legal, esta ficando interessante esta brincadeira, por enquanto sem nenhum perigo!

Para que possamos realizar o processo de reescrita de uma ou mais páginas de dados, vou selecionar duas páginas (256 e 258) e seus valores para utilizar em nosso cenário, conforme a Tabela 1 apresentada abaixo:

PageID Codigo ValorGuid
(1:256:10) 20 6460AAB3-AD12-47BB-B179-8C1930B1A287
(1:258:1) 120 AEF17F9D-D838-4FEF-B723-CA3658D03319

Tabela 1 – Relação de páginas de dados e valores que iremos utilizar.

Já sabemos com quais estruturas vamos fazer o processo de reescrever suas estruturas, devemos então preparar nosso banco de dados para que nos possibilite a realização desta tarefa, desta forma, utilizaremos o Bloco de Código 5, apresentado abaixo:

— Bloco de Código 5 — Alterando a forma de acesso do banco de dados RestoreDatabasePage —

— Preparando-se para corromper a estrutura de páginas —
Use Master
Go

— Limitando a conexão do Banco de Dados para Single_User —
Alter Database RestoreDatabasePage
Set Single_User
With Rollback Immediate
Go

Ótimo, acabamos de limitar o acesso físico e lógico do nossa banco de dados para Single_User, desta forma, nenhuma outra conexão ou solicitação de acesso será permitida ao mesmo, neste momento temos acesso único e exclusivo.

O passo seguinte, consiste na consulta da estrutura da página de dados 256 e posteriormente na procura do valor 6460AAB3-AD12-47BB-B179-8C1930B1A287 armazenado no Slot 10, vamos então executar o Bloco de Código 6, apresentado abaixo:

— Bloco de Código 6 — Obtendo as informações sobre a página de dados 256 e pesquisando valor 6460AAB3-AD12-47BB-B179-8C1930B1A287 —

Para que possamos obter as informações de retorno apresentadas pelos comandos DBCC – Database Command Console, precisamos fazer uso do comando Dbcc TraceOn ativando a Trace Flag 3604 que orienta e informa ao Microsoft SQL Server que o mesmo deverá apresentar logo após a execução dos comandos DBCCs seus respectivos resultados.

— Obtendo informações sobre os slots de alocação de dados —
Dbcc TraceOn (3604)
Go

Seguindo nossa caminhada, vamos utilizar o comando DBCC Page, comando que vai nos possibilitar obter o conjunto de informações internas que formam a estrutura da nossa tabela, neste caso, vamos buscar toda estrutura da página de dados de número 256.

— Procurando valor 6460AAB3-AD12-47BB-B179-8C1930B1A287 e guardar slots —
Dbcc Page (‘RestoreDatabasePage’, 1, 256, 3);
Go

A Figura 2 apresentada abaixo, ilustra uma parte da estrutura interna da página de dados 256, apresentando sua área de buffer e page hearder:
Figura 2 – Estrutura interna da página de dados 256.

Pois bem, precisamos agora procurar o valor 6460AAB3-AD12-47BB-B179-8C1930B1A287 dentro da área de dados desta mesma página, afim de encontramos o refiro Slot 10 que armazena este dado.

Para que possamos encontrar o referido valor clique na guia de mensagens do Management Studio e preciso posteriormente a tecla de atalho CTRL + F, informando o valor na campo de busca.

A Figura 3 ilustra o 6460AAB3-AD12-47BB-B179-8C1930B1A287 localizado na estrutura interna da página de dados 256:
Figura 3 – Valor 6460AAB3-AD12-47BB-B179-8C1930B1A287 localizado.

O mesmo procedimento deverá ser feito para página 258 referente ao código 120 e ValorGuid AEF17F9D-D838-4FEF-B723-CA3658D03319.

Além disso, recomendo que você anote as informações referente OffSet e Length de dados valor pesquisado em sua referida página, pois ambos serão utilizado no procedimento de reescrita, mas como eu sou bonzinho, a Tabela 2 apresentada abaixo destaca estes valores:

Collumn Offset Length ValorGuid
2 0x8 16 6460aab3-ad12-47bb-b179-8c1930b1a287
2 0x8 16 AEF17F9D-D838-4FEF-B723-CA3658D03319

Tabela 2 – Informações sobre Offset e Length dos respectivos ValorGuid.

Agora chegou a tão esperada hora de suar o barraco (kkkk), não é bem assim, mas chegou o momento de reescrevermos a estrutura das páginas de dados: 256 e 258, através do comando DBCC WritePage declarado no Bloco de Código 7 apresentado na abaixo:

— Reescrevendo a página de dados 256 no OffSet 0x8 —
Dbcc WritePage (‘RestoreDatabasePage’, 1, 256, 8, 16, 0x00000000000000000000000000000001, 1)
Go

— Reescrevendo a página de dados 256 no OffSet 0x8 —
Dbcc WritePage (‘RestoreDatabasePage’, 1, 258, 8, 16, 0x00000000000000000000000000000001, 1)
Go

Se você conseguiu realizar o processamento destes dois comandos DBCC WritePage, isso significa que neste momento as páginas de dados 256 e 258 estão apresentando inconsistência em suas estruturas, algo que podemos comprovar através da execução do Bloco de Código 8, apresentado abaixo:

— Bloco de Código 8 – Verificando a Integridade da TabelaCorrompida —
— Alterando o acesso ao Banco de Dados para Multi_User —
Alter Database RestoreDatabasePage
Set Multi_User
Go

— Realizar testes de integridade consultando dados na TabelaCorrompida —
Use RestoreDatabasePage
Go

Select Count(Codigo) From TabelaCorrompida
Go

Ao realizarmos o comando Select Count() para tentarmos contar a quantidade de linhas de registros existentes na TabelaCorrompida, o Management Studio nos retorna a seguinte mensagem de erro:
Msg 824, Level 24, State 2, Line 162
SQL Server detected a logical consistency-based I/O error: incorrect checksum (expected: 0x4bd220eb; actual: 0xcb53a034). It occurred during a read of page (1:256) in database ID 11 at offset 0x00000000200000 in file ‘S:\MSSQL-2017\Data\RestoreDatabasePage.mdf’. Additional messages in the SQL Server error log or operating system error log may provide more detail. This is a severe error condition that threatens database integrity and must be corrected immediately. Complete a full database consistency check (DBCC CHECKDB). This error can be caused by many factors; for more information, see SQL Server Books Online.

Vamos avançar mais ainda, estamos nos aproximando do final deste post, agora que nosso ambiente esta danificado podemos fazer uso da opção Page existente no comando Restore Database que vai nos permitir restaurar a estrutura física e lógica da nossa tabela, sendo assim, vamos utilizar o Bloco de Código 9, apresentado abaixo:

— Bloco de Código 9 – Iniciando o processo de restauração e recuperação das páginas de dados —
— Realizando a Restauração das Páginas de Dados —
Use Master
Go

— Restore Database Page —
Restore Database RestoreDatabasePage
PAGE=’1:256, 1:258′ — Informando os números de páginas
From Disk = N’S:\MSSQL-2017\Backup\RestoreDatabasePage-Backup-Full.bak’
With File = 1, — Especificando o arquivo de dados
NoRecovery, — Não liberando o banco para acesso
Stats = 10
Go

 

Perfeito, realizamos o procedimento se restauração das páginas de dados 256 e 258 sem restaurar toda estrutura do nosso banco, agora podemos realizar um novo teste e verificar se a a estrutura da nossa TabelaCorrompida encontra-se funcional, conforme apresenta o Bloco de Código 10 a seguir:

— Bloco de Código 10 — Realizando um novo teste de integridade consultando dados na TabelaCorrompida —
Use RestoreDatabasePage
Go

Select Count(Codigo) From TabelaCorrompida
Where Codigo Not Between 20 And 120
Go

E para nossa surpresa o Management Studio retornou mais uma vez outra mensagem de erro:
Msg 829, Level 21, State 1, Line 186
Database ID 11, Page (1:256) is marked RestorePending, which may indicate disk corruption. To recover from this state, perform a restore.

Esta mensagem nos informa que não podemos realizar o acesso a TabelaCorrompida pois neste momento a página 256 esta marcado como pendente de restauração, este é um comportamento normal apresentado pelo SQL Server, pois o mesmo depende da realização de um backup de log e posteriormente da restauração (conhecido como Tail Log) para realizar a limpeza e desmarcar esta página de dados como pendente.

Para tal procedimento, utilizaremos o Bloco de Código 11, apresentado abaixo:

— Bloco de Código 11 — Realizando Backup Log e Restore Log (Tail Log) —
— Backupear o Log e Restaura para Liberar páginas marcadas como pendentes —
Use Master
Go

Backup Log RestoreDatabasePage
To Disk = ‘S:\MSSQL-2017\Backup\RestoreDatabasePage-Backup-Log.bak’
With NoFormat,
Init,
Name = N’RestoreDatabasePage-Backup-Log’,
Stats=10
Go

— Restaurar Log —
Restore Log RestoreDatabasePage
From Disk = ‘S:\MSSQL-2017\Backup\RestoreDatabasePage-Backup-Log.bak’
With Recovery,
Replace,
Stats = 10
Go

Acredito que o procedimento de Backup Log e Restore Log tenha ocorrido normalmente, basta agora realizar o último teste de acesso a TabelaCorrompida para poder consultar todos os dados armazenados na mesma, conforme apresenta o Bloco de Código 12:

— Bloco de Código 12 — Realizar último teste de integridade consultando dados na TabelaCorrompida —
Use RestoreDatabasePage
Go

A Figura 4 apresentada abaixo ilustra a massa de dados existente na TabelaCorrompida, após o procedimento de restauração e recuperação das páginas de dados: 256 e 258.
Figura 4 – Relação de dados existentes na TabelaCorrompida, recuperados após o procedimento de Restore Database Page.

— Obtendo a quantidade de registros armazenados na TabelaCorrompida —
Select Parcial=(Select Count(Codigo) From TabelaCorrompida Where Codigo Not In (20,120)),
Geral=(Select Count(Codigo) From TabelaCorrompida)
Go

Show de bola, muito bom, conseguimos, seguimos todos os passos desde a criação do nosso ambiente, inserção de dados, identificação das páginas e suas estrutura, reescrita na estrutura das páginas e o tão esperado procedimento de restauração.

Com isso chegamos ao final de mais um post da sessão Dica do Mês, antes de encerrarmos, gostaria de contar com a sua participação neste post, respondendo a enquete abaixo:


Referências

https://docs.microsoft.com/en-us/sql/relational-databases/backup-restore/restore-pages-sql-server?view=sql-server-2017

https://docs.microsoft.com/en-us/sql/t-sql/statements/restore-statements-transact-sql

https://docs.microsoft.com/en-us/sql/t-sql/statements/backup-transact-sql

https://www.mssqltips.com/sqlservertip/1925/how-to-use-the-sql-server-sysfnphyslocformatter-undocumented-function/

https://blogs.msdn.microsoft.com/fcatae/2016/04/12/dbcc-page/

https://docs.microsoft.com/pt-br/sql/t-sql/database-console-commands/dbcc-transact-sql

http://www.sqlskills.com/BLOGS/PAUL/post/SQL-Server-2008-New-%28undocumented%29-physical-row-locator-function.aspx

https://blogs.msdn.microsoft.com/sqlserverstorageengine/2006/12/13/more-undocumented-fun-dbcc-ind-dbcc-page-and-off-row-columns/

https://docs.microsoft.com/en-us/sql/t-sql/database-console-commands/dbcc-checkdb-transact-sql

Posts Anteriores

https://pedrogalvaojunior.wordpress.com/2018/07/26/dica-do-mes-ocultando-uma-instancia-em-execucao-do-microsoft-sql-server/

https://pedrogalvaojunior.wordpress.com/2018/04/25/dica-do-mes-sql-operations-studio-view-as-chart/

https://pedrogalvaojunior.wordpress.com/2018/03/14/dica-do-mes-microsoft-sql-server-2017-sql-graph-databases/

https://pedrogalvaojunior.wordpress.com/2018/01/24/dicadomes-sqlservertoolsuiteintroduction/

Conclusão

Como já destaquei em outros posts, a cada nova versão, atualização e correção a Microsoft transforma o SQL Server em um produto surpreende, ainda mais na sua capacidade e versatilidade de permitir aos profissionais de tecnologia, administradores de bancos de dados, programadores, entre outros, utilizar recursos nativo e também os não documentados oficialmente como um elemento capaz de se superar e sobreviver a  inúmeras falhas ou situações de perdas de dados.

No post de hoje, mais uma vez este foi constatado, a possibilidade através do comando DBCC Page de se obter informações sobre as páginas de dados, o comando DBCC WritePage (muito cuidado com ele) sensacional na sua funcionalidade em permitir uma reescrita de dados na estrutura das páginas que formam uma tabela, e principalmente a não documentada function sys.fn_physLocFormatter que de forma simples, fácil e confiável nos apresenta a distribuição de páginas de dados que compõem nossas tabelas em conjunto com os respectivos slots que armazenam nosso dados.

Acredito que você tenha conseguido entender e observar como consultamos a estrutura de páginas, a forma que alteramos seu conteúdo forçando uma reescrita de dados e depois como conseguimos através do comando Restore Database Page recuperar estas áreas.

Este é o fantástico Microsoft SQL Server, produto tão fascinante que a cada dia eu não consigo deixar de querer estudar e conhecer mais ainda.

Agradecimentos

Agradeço a você por sua atenção e visita ao meu blog. Fique a vontade para enviar suas críticas, sugestões, observações e comentários.

Nos encontramos no próximo post da sessão Dica do Mês a ser publicado no mês de dezembro.

Um forte abraço, sucesso, até mais…

Dica do Mês – Ocultando uma instância em execução do Microsoft SQL Server


Muito boa noite, você que esta aqui fazendo mais uma visita ao meu blog.

Seja mais uma vez, bem vindo, que prazer enorme contar com a sua presença, em mais um post da sessão Dica do Mêssessão dedicada a compartilhar bimestralmente dicas, novidades, curiosidades e demais informações relacionadas ao Microsoft SQL Server, Banco de Dados e Tecnologias de Banco de Dados.

Neste post, quero dividir com você uma funcionalidade que utilizei no decorrer deste mês de julho para um dos meus clientes, não posso dizer que é uma funcionalidade ou recurso do Microsoft SQL Server, na verdade é uma propriedade que podemos aplicar as nossas instâncias ou servidores em execução em nossos ambientes para tentar aplicar mais uma camada de segurança sem ter a necessidade do uso de ferramentas de terceiros ou configurações avançadas, pensamento sempre em minimizar e dificultar possíveis tentativas de invasão.

Você pode ter ficado um pouco confuso ou até mesmo curioso com o título desta dica, mas é justamente isso que vamos conhecer e aprender da Dica do Mês que estou compartilhando, uma possibilidade de fazer com que ferramentas invasoras ou até mesmo o próprio SQLCMD ferramenta nativa do Microsoft SQL Server utilizada em linha de comando não consiga identificar quais instâncias estão em execução localmente ou remotamente.

Além disso, esta funcionalidade, também omite a visibilidade de identificação de nossas instâncias para o SQL Server Browser, serviço utilizado pelo Microsoft SQL Server para realizar troca de mensagens afim de identificar e possibilitar comunicação entre instâncias em execução locais ou remotas.

E ai, esta curioso em saber um pouco mais sobre esta nova forma de apresentar seus dados? Eu estou, e não vejo a hora de poder dividir com você um pouco deste recurso.

Então, vamos em frente, vou tentar mitigar a sua curiosidade e ao mesmo também satisfazer os meus objetivos. Sendo assim, seja bem vindo ao post – Dica do Mês – Ocultando uma instância em execução do Microsoft SQL Server.


Introdução

Atualmente o número de incidentes relacionados com tentativas de invasões, falhas de segurança, vulnerabilidades e vírus tem sofrido um aumento de forma assustadora no Brasil segundo os estudos e análises de estatísticas realizadas pelo CERT.BR – Centro de Estudos, Resposta e Tratamento de Incidentes de Segurança no Brasil.

Tendo como base a Figura 1 apresentado abaixo, que representa gráfico de estatísticas de incidentes reportados ao CERT.BR em 2017, temos uma real dimensão do quando nossos dados processados diariamente podem em algum momento cair em mãos erradas, situação de extrema preocupação para qualquer indivíduo que atualmente utiliza os recursos de tecnologia ligados a internet.
Figura 1 – Gráfico de Estatísticas de Incidentes Reportados ao CERT.BR.

Caminhando mais um pouco, o foco deste post não é falar sobre invasões, muito menos análises de ameaças, mas a funcionalidade que vou apresentar como já destacado esta relacionada com medidas de segurança.

Analisando os números

Abordando um pouco do gráfico apresentado anteriormente, vou fazer uma rápida análise para justificar o porque se tornou tão importante a preocupação com ações de segurança. Esta análise será aplicada através dos números apresentados pelo gráfico do CERT.BR para os últimos quatro anos: 2017, 2016, 2015 e 2014, números que nos permitiram ter a real noção do que esta acontecendo no Brasil, servindo como suporte para nos ajudar e dimensionar os riscos que estamos diariamente correndo.

Para suportar e fortalecer nosso entendimento, elaborei uma simples Tabela denominada Tabela 1 que apresenta a diferença em números de incidentes anuais, e suas respectivas diferenças percentuais no que se relaciona aos de incidentes reportados pelo CERT.BR.

A seguir apresento a Tabela 1 – Incidentes entre os anos de 2014 até 2017:

Ano Total de Incidentes Anuais Diferença – Número de Incidentes – Ano Anterior x Ano Posterior Variação Percentual – Ano Anterior x Ano Posterior
2017 833.775 186.663 22,39%
2016 647.112 -75.093 -11,60%
2015 722.205 -324.826 -44,98%
2014 1.047.031

Tabela 1 – Análise dos números de incidentes reportados anualmente pelo CERT.BR.

Aplicando uma simples analogia, podemos dizer claramente que entre os anos de 2014 e 2017 o número de incidentes reportados pelo CERT.BR apresentou uma diminuição de 25,58%, algo de aproximadamente 213.256 (Duzentos e Treze Mil, Duzentos e Cinquenta e Seis) incidentes a menos reportados, evidência que não nos permite deixar de se preocupar.

Por outro lado se analisarmos especificamente o último ano, sendo este o ano de 2017 tivemos um aumento de 22,39% no número de incidentes em relação ao ano de 2016, mais assertivamente um crescimento de 186.339 (Cento e Oitenta de Seis Mil, Trezentos e Trinta e Nova).

Em contra partida, se iniciarmos uma outra análise a partir do no ano de 2015 tivemos uma diminuição de mais de 324.000 (Trezentos e Vinte e Quatro Mil) no número de incidentes reportados ao CERT.BR em relação ao ano anterior, no caso 2014.

E ai que fica a pergunta, esta variação pode representar que as empresas, profissionais de tecnologias e usuários comuns estão se preocupando cada vez mais com a sua segurança, ou os possíveis invasores estão perdendo força?

Esta é uma pergunta que sinceramente falando é de difícil resposta ou afirmação, no meu ponto de vista, ela representa reflexão mais profunda, não somente voltada para área de tecnologia, mas sim para o comportamento social de cada individuo e empresa.

Vamos avançar ainda mais e conhecer a funcionalidade que poderá nos ajudar a aplicar mais uma “camada de segurança” em nossas instâncias Microsoft SQL Server.

Conhecendo a Propriedade Hide Instance (Instância Oculta)

Daqui em diante não vou falar mais de incidentes, invasões e números relacionados a estes elementos, chegou a hora de conhecer esta tal “camada de segurança”, conhecida como propriedade Hide Instance existente dentro da ferramenta SQL Server Configuration Manager, a qual é instalada por padrão em conjunto com nossas instâncias Microsoft SQL Server.

Acredito que você deve conhecer a ferramenta SQL Server Configuration Manager, se ainda não conhece, fique tranquilo, basta em seu Windows através do botão iniciar começar a digitar: SQL Server 2016 ou 2017 Configurationque a ferramenta de pesquisa vai encontrar.

Para ilustrar esta ferramenta, a Figura 2 apresenta sua tela principal:

Figura 2 – Ferramenta – SQL Server Configuration Manager.

Muito bem, espero que você tenha conseguido encontrar este ferramenta em seu ambiente, o próximo passo é justamente identificar a instância que você deseja ocultar “esconder”, no meu cenário tenho duas instâncias instaladas localmente, denominadas:

  • WIN10PRO – Microsoft SQL Server 2016 Enterprise; e
  • WIN10PRO\MSSQLServer2017 – Microsoft SQL Server 2017 Enterprise.

A instância WIN10PRO\MSSQLServer2017 possui aplicada a propriedade Hide Instance, neste caso se tentarmos realizar uma pesquisa das instâncias em execução da minha máquina através da ferramenta de prompt-de-comando SQLCMD em conjunto com o parâmetro -L seu nome omitido da lista de instâncias locais, ao contrário da instância WIN10PRO a qual não possui aplicada a mesma propriedade.

Aplicando a propriedade Hide Instance

Para aplicar a propriedade Hide Instance a uma instância SQL Server, necessitamos estar com o SQL Server Configuration Manager em execução, logo após escolher no painel a esquerda a opção: SQL Server Network Configuration, conforme apresenta a Figura 3 a seguir:

Figura 3 – SQL Server Configuration Manager, opção SQL Server Network Configuration.

Observe que logo após escolher esta opção, o SQL Server Configuration Manager apresenta a relação de instância instaladas em meu ambiente conforme já destaquei anteriormente.

Nosso próximo passo será justamente encontrar a propriedade Hide Instance, para isso, vou selecionar a instância WIN10PRO\MSSQLServer2017, como já abordei a mesma possui ativada este propriedade, sendo assim, vou clicar com o botão da direita do mouse sobre a instância e escolher a opção Properties (Propriedades), conforme apresenta a Figura 4 abaixo:

Figura 4 – Menu Popup – Opção Propriedades.

Show, simples e prático, logo após clicar na opção Properties o SQL Server Configuration Manager deve ter apresentado a tela de propriedades “externas” que podemos aplicar para nossa instância, sendo elas:

  • Force Encryption; e
  • Hide Instance (Esconder, Ocultar ou Omitir).

A Figura 5 apresenta a relação de propriedades “externas”:

Figura 5 – Propriedades externas disponíveis para a instância WIN10PRO\MSSQLServer2017.

Muito bem, sem mais delongas, note que a propriedade Hide Instance possui o valor de True (Verdadeiro) aplicado, sendo assim, a capacidade de ocultar, esconder ou omitir a visibilidade desta instância tanto para o SQL Server Browser como também para o SQLCMD esta ativada.

Sequência de passos:

  1. Abrir – SQL Server Configuration Manager;
  2. Acessar o guia SQL Server Network Configuration;
  3. Clicar com o botão da direita sobre a instância WIN10PRO\MSSQLSERVER2017;
  4. Selecionar a propriedade Hide Instance e escolher o valor True;
  5. Clicar OK;
  6. Acessar a guia SQL Services;
  7. Clicar com o botão da direita sobre a instância WIN10PRO\MSSQLSERVER2017; e
  8. Selecionar a opção Restart.

Nosso último passo será justamente comprovar a veracidade do uso desta propriedade.

Estamos quase no final….

Testando a aplicação da propriedade Hide Instance

Como já destacado anteriormente, a partir do momento em que a propriedade Hide Instance encontra-se habilitada a ferramenta SQLCMD através do parâmetro -L não consegui identificar e apresentar o nome da respectiva instância, sendo assim, este será justamente nosso simples ambiente de teste.

Vou então abrir a ferramenta Prompt-de-Comando (CMD) e logo após digite a linha de comando: SQLCMD -L, conforme apresenta a Figura 6:

Figura 6 – Lista de instâncias identificadas e apresentadas pela ferramenta SQLCMD.

E ai esta o resultado a ferramenta SQLCMD não conseguiu identificar a presença da instância WIN10PRO\MSSQLSERVER2017, sendo que a mesma encontra-se em execução.

Para finalizar, vou seguir os passos apresentados anteriormente para acessar a propriedade Hide Instance e desativar a possibilidade de omitir o nome da instância, logo na sequência executar novamente a linha de comando SQLCMD -L e verificar seu resultado:

  1. Abrir – SQL Server Configuration Manager;
  2. Acessar o guia SQL Server Network Configuration;
  3. Clicar com o botão da direita sobre a instância WIN10PRO\MSSQLSERVER2017;
  4. Selecionar a propriedade Hide Instance e escolher o valor False;
  5. Clicar OK;
  6. Acessar a guia SQL Services;
  7. Clicar com o botão da direita sobre a instância WIN10PRO\MSSQLSERVER2017;
  8. Selecionar a opção Restart;
  9. Abrir o Prompt-de-Comando; e
  10. Executar a instrução: SQLCMD -L

Observação: Vale ressaltar que tanto para ativar como também para desativar a propriedade Hide Instance, é necessário realizar o procedimento de reinicialização do serviço do Microsoft SQL Server referente a instância selecionada.

Conforme prometido, após realizar os passos apresentados anteriormente, eis aqui o resultado da execução da linha de comando: SQLCMD -L, conforme apresenta a Figura 7 a seguir:

Figura 7 – Relação de instância identificadas pela ferramenta SQLCMD.

Como um passe de mágica, límpido e transparente, a ferramenta SQLCMD consegui identificar a presença da instância WIN10PRO\MSSQLSERVER2017, exibindo assim seu nome na lista de instâncias e servidores identificados.

Isso não é sensacional? Eu tenho a certeza que sim e espero que você também pense desta forma.

Com isso chegamos ao final de mais um post da sessão Dica do Mês, antes de encerrarmos, gostaria de contar com a sua participação neste post, respondendo a enquete abaixo:


Referências

https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/hide-an-instance-of-sql-server-database-engine?view=sql-server-2017

https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/configure-the-database-engine-to-listen-on-multiple-tcp-ports?view=sql-server-2017

https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/configure-a-windows-firewall-for-database-engine-access?view=sql-server-2017

https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/connect-to-sql-server-through-a-proxy-server-sql-server-configuration-manager?view=sql-server-2017

Posts Anteriores

https://pedrogalvaojunior.wordpress.com/2018/04/25/dica-do-mes-sql-operations-studio-view-as-chart/

https://pedrogalvaojunior.wordpress.com/2018/03/14/dica-do-mes-microsoft-sql-server-2017-sql-graph-databases/

https://pedrogalvaojunior.wordpress.com/2018/01/24/dicadomes-sqlservertoolsuiteintroduction/

https://pedrogalvaojunior.wordpress.com/2017/11/01/dicadomessql2017novascolunasinternas/

Conclusão

Pensar em manter nossos ambientes e dados seguros é um preocupação que todos devemos ter, independente da situação e importância.

Fazer uso de recursos, ferramentas, funcionalidades ou até mesmo a adoção de simples práticas podem nos ajudar a garantir cada vez mais a sobrevivência e proteção destes preciosos elementos.

Pensando justamente desta forma, o uso da propriedade Hide Instance deve ser adotada em nossas instâncias ou servidores, como uma possível “camada de segurança”, afim de dificultar a identificação e apresentação destes recursos.

Agradecimentos

Agradeço a você por sua atenção e visita ao meu blog. Fique a vontade para enviar suas críticas, sugestões, observações e comentários.

Nos encontramos no próximo post da sessão Dica do Mês a ser publicado no mês de setembro.

Valeu, bom final de noite….