Mostrando postagens com marcador SQL. Mostrar todas as postagens
Mostrando postagens com marcador SQL. Mostrar todas as postagens

sábado, 24 de outubro de 2020

TDD no SQL com tSQLt

 

A utilização de teste é uma realidade muito comum no desenvolvimento de aplicativos, porém banco de dados é tratada como uma forma de exceção quando falamos da utilização do método desenvolvimento orientado a testes, principalmente pela falta de uma ferramenta integrada que possibilite a criação de testes, classes, além da metrificação dos resultados da execução dos testes.

O tSQLt é uma ferramenta que oferece uma estrutura de testes para ser aplicado em banco de dados SQL, o tSQLt permite implementar testes de unidade em T-SQL, também fornece recursos como: testes dentro das transações, agrupamento dos testes em classes, saída em texto simples ou XML e o principal de criar clonar de tables, views, functions e procedure para utilizar em simulação nos testes sem interferir nas estruturas reais.

O processo para utilização é bem simples e vamos demonstrar desde a instalação e criação de um teste e sua execução.

  1. Instalação do tSQLt

  • Baixe tSQLt do site tSQLt.ORG

  • Acesse ou crie um novo banco de dados

  • Execute o script tSQLtClass.SQL no banco de dados


Installed at 2020-10-24 18:23:21.390
+-----------------------------------------+
|                                         |
| Thank you for using tSQLt.              |
|                                         |
| tSQLt Version: 1.0.5873.27393           |
|                                         |
+-----------------------------------------+
  1. Efetuar a criação de “Classes” para agrupar o teste

EXEC tSQLt.NewTestClass 'UnitTestClass';

Esse comando irá criar uma classe que poderá ser utilizada para executar somente os testes que estiverem associadas à ela, na prática o SQL criará um “Schema” com esse nome.

  1. Criando um teste

CREATE OR ALTER PROC [UnitTestClass].[Test Exists Function CalculateBestQuote]
AS
BEGIN
  --Arrange
 
  --Act
  
  --Assert
   EXEC tSQLt.AssertObjectExists @ObjectName = N'fnCalculateBestQuote'
END
GO

Importante, toda procedure que representa um teste deve obrigatoriamente iniciar com a palavra “Test”, como o banco de dados podem conter estrutura que podem não existir, diferente de código estático, existe um Assert específico que efetua a validação da existência do objeto, no caso do exemplo, ele está verificando se a function “fnCalculateBestQuote” existe no banco de dados.

  1. Executando os testes

    EXEC tsqlt.RunTestClass 'UnitTestClass'

Através do comando, todos os testes que estão associados a classe referida, será executado exibindo as mensagens de erros, os resultados esperados e um resumo dos testes.

[UnitTestClass].[Test Exists Function CalculateBestQuote] failed: (Failure) 'fnCalculateBestQuote' does not exist
 
+----------------------+
|Test Execution Summary|
+----------------------+
 
|No|Test Case Name                                           |Dur(ms)|Result |
+--+---------------------------------------------------------+-------+-------+
|1 |[UnitTestClass].[Test Exists Function CalculateBestQuote]|    127|Failure|
-----------------------------------------------------------------------------
Msg 50000, Level 16, State 10, Line 1
Test Case Summary: 1 test case(s) executed, 0 succeeded, 1 failed, 0 errored.
-----------------------------------------------------------------------------

  1. Criando a function 

CREATE OR ALTER FUNCTION fnCalculateBestQuote
(
    @BaseValue decimal(10,2),
@Fator decimal(6,2)
)
RETURNS Decimal(15,2)
AS
BEGIN
    RETURN @BaseValue / @Fator * 2;
END
GO

Após a execução dos testes e da falha, devemos escrever o código que satisfaça a regra de negócio esperada.

  1. Executando o teste novamente

EXEC tsqlt.RunTestClass 'UnitTestClass'

O resultado dos testes será com sucesso

+----------------------+
|Test Execution Summary|
+----------------------+
 
|No|Test Case Name                                           |Dur(ms)|Result |
+--+---------------------------------------------------------+-------+-------+
|1 |[UnitTestClass].[Test Exists Function CalculateBestQuote]|      6|Success|
-----------------------------------------------------------------------------
Test Case Summary: 1 test case(s) executed, 1 succeeded, 0 failed, 0 errored.
-----------------------------------------------------------------------------

Portanto, agora ficará mais fácil detectar bugs antes mesmo de conectar com seu código de backend, simplesmente executando os testes no banco de dados.

Existem várias funções desenvolvidas para validações, além claro da parte de clonar tabelas e afins para criar massa de testes, existe uma vasta documentação em https://tsqlt.org/full-user-guide/

Na GFT praticamos TDD em sessão de Coding Dojo que ocorrem a cada 15 dias em sessões online, elas são abertas para todos participarem, basta acessar //meetup.com/GFTBrasil, escolher o melhor dia e horário para você praticar.


Marcelo Goberto de Azevedo 

Arquiteto na GFT Brasil

//marcelogoberto.com.br


domingo, 14 de junho de 2020

Dicas para melhorar o entendimento das SQL Querys

Consultas em SQL são basicamente códigos no final, logo é importantíssimo termos a preocupação de oferecer um código claro e objetivo para aumentar a manutenibilidade dele por outros desenvolvedores. Comandos mal formatados e/ou com escritas confusas podem aumentar mais erros e uma falta geral de motivação para revisar seu trabalho. Para quem simplesmente escreve a consulta pode fazer sentido e até funcionar, porém é fundamental que o código esteja num melhor formato possível para aumentar sua qualidade, vamos a alguma regras que podem ajudar.

Seja consistente e corente com a formatação

SELECT primeiroNome, count(*) from
Usuários WHERE ultimo_nome = 'silva' Group by primeiroNome

Vamos analisar alguns pontos:

  • Veja que algumas partes estão em maiúsculas e outras não, procure manter um padrão único, por exemplo todas as palavras reservadas.
  • É confuso identificar o que é coluna ou o que é comando
  • A coluna do SELECT está em "camelCase", a usada no WHERE está "snake_case" e o nome da tabela em "PascalCase", crie um padrão geral, se começou errado, conserte.
  • A utilização de caracter especial em definição de nomes, como na tabela Usuários

Veja um exemplo como deveria ser:

SELECT primeiro_nome, COUNT(*) from
usuarios WHERE ultimo_nome = 'silva' GROUP BY by primeiro_nome 

Use e Abuse da Identação 

SELECT g.id, COUNT(u.id) FROM usuarios u JOIN gruopos g on u.grupo_chave
= g.chave WHERE u.nome = 'Marcelo' AND  u.sobrenome
= 'Silva'  GROUP BY g.chave ORDER BY COUNT(u.chave) desc 

Para uma consulta pequena pode não fazer diferença para leitura quando tudo está sem um padrão de separação, agora imagine aquelas longas procedures com todos os comandos encavalados, não é mesmo?

Veja se o resultado fica melhor para o entendimento: 

SELECT 
	  g.id
	, COUNT(u.id) 
FROM usuarios u 
	JOIN gruopos g on u.grupo_chave = g.chave 
WHERE 
	    u.nome = 'Marcelo' 
	AND u.sobrenome = 'Silva'
GROUP BY 
	g.chave 
ORDER BY 
	COUNT(u.chave) desc

Dica: A utilização da virgula (,)antes de cada campo no SELECT, ou das conjunções AND / OR no WHERE, GROUP BY, ORDER BY facilita a identificação visual onde se inicia ou termina o grupo de campo, além de fornecer uma forma agíl de comentar um campo 

Se você utilizar 2 ou 4 espaços não surti efeito considerável, o importante é só manter o padrão em toda a codificação, a simplesmente utilização dessa formatação farão seu colegas adorarem ver suas consultas quase como obras de arte. 😃

Utilize sempre "Aliases" 

SELECT
    u.chave
    , u.nome
    , t.chave
    , t.nome
    , (SELECT COUNT(*) FROM titulos where nome = t.nome)
FROM usuarios u
    JOIN titulos t on u.titulo_chave = t.chave 

O resultado dessa consulta será: 

chave

nome

chave

nome

count

1

Marcelo Goberto

4

Arquiteto

6

Novamente num cenário minimalista é possível identificar o que é cada conteúdo, agora imagine isso num longo resultado com várias colunas, por isso é fundamental que você nomeie cada coluna para que possa facilitar o entendimento.

Veja como fica o resultado da mesma consulta acima com ajustes 

SELECT
   u.chave AS usuario_chave
   , u.nome AS usuario_nome
   , t.chave AS titulo_chave
   , t.nome AS titulo_nome
   , (SELECT COUNT(*) FROM titulos where nome = t.nome) AS qtde_titulos
FROM usuarios u
JOIN titulos t on u.titulo_chave = t.chave

O resultado dessa consulta será 

usuario_chave

usuario_nome

titulo_chave

titulo_nome

qtde_titulos

1

Marcelo Goberto

4

Arquiteto

6


Utilize números nas clausulas GROUP BY e ORDER BY 

Neste caso essa é uma preferência pessoal que acredito que auxilia muito no organização de uma consulta, veja um exemplo com essa aplicação 

SELECT
   nome
    , sobrenome
    , COUNT(*) AS total
FROM usuarios
GROUP BY 1, 2
ORDER BY 3 desc 

Algumas vantagens na adoção desse formato são:

  • Economia de linhas: a utilização de muitas colunas em GROUP ou ORDER não aumentará sua consulta, pois todos estarão enfileiradas
  • Manutenção: Se desejar trocar o agrupamento ou a ordenação, basta trocar as colunas de lugar dentro da clausula SELECT

Esses foram alguns pontos que sempre considero na hora de escrever uma consulta, não existe um melhor padrão ou formato único para SQL, mas com certeza existe o desafio que procurar fazer um ótimo trabalho que possa ter sua manutenção facilitada para os próximos e quem sabe para nós mesmo, porque se todos tivermos um consenso que garantir sempre um excelente padrão de código, todos se sairão ganhando.

Marcelo Goberto de Azevedo

Arquiteto na GFT Brasil

//marcelogoberto.com.br


quinta-feira, 13 de fevereiro de 2020

Principais Razões para uma Péssima Performance no SQL


Esses são os principais pontos que devem ser observados quando da construção de uma base de dados, porque alguns erros podem simplesmente transformar a performance numa verdadeira carroça, e acelerar uma carroça pode até funcionar, mas nãos será por muito tempo que ela vai aguentar o tranco. Vamos ver algumas ações que devemos evitar para garantir um bom desempenho de nossa base de dados.


#1: Desenho de Estrutura Ruim

Boa parte do sucesso de uma aplicação se sustenta nos dados que serão providos e nas velocidades em que eles estarão disponíveis. Por isso é importantíssimo a excelente na construção de uma estrutura do banco de dados, porque ela será a espinha dorsal para tudo que for construído em volta, listamos alguns erros que devem ser evitados para garantir um desenho funcional.

Normalização Baixa
Redundância de informações no banco de dados
Baixa integridade de referência entre tabelas (chaves primárias e estrangeiras)
Chaves primárias complexas demais (muitos campos)
Falta de teste de stress no desenho (cenários de crescimento dos dados)
     

#2: Queries e Códigos Ineficientes

Se você tem uma base sólida e bem construída, agora chegou a parte de criar as principais estruturas que transportaram e transformarão os dados, essas partes são muito importantes, porque será através delas que os dados serão coletados e entregues nas pontas, esses erros devem ser evitados:

Utilizar [NOT IN] ou [IN] em vez de [NOT EXISTS] ou [EXISTS]
Usar cursores ou loop fakes em vez de [INSERT… SELECT] ou [SELECT… INTO TABLE]
Usar [SELECT *] em vez de apenas os nomes de coluna necessários
Esquecendo de usar parênteses ao usar operadores lógicos [OR] ou [AND]
Alinhamento de subconsultas criando um plano de execução complexo
Usando funções na coluna indexada na cláusula [WHERE]
Uso excessivo de funções escalares definidas pelo usuário
Uso desnecessário de [DISTINCT] em qualquer lugar
SQL dinâmico

#3: Estratégia de Indicies Pobre

Os índices podem ser considerados aceleradores de um banco de dados, porém a criação, definição e utilização deve ser estudada e mensurada para que eles possam oferecer ganhos, porque indicies mal dimensionados à revelia podem acabar tendo um efeito contrário, por isso esses erros devem ser evitados:

Indexar todas chaves estrangeiras
Indexar todas as colunas de uma tabela
Muitos índices para uma simples coluna
Preferir tabelas sem índice clusterizado
Subindexiar suas tabelas
Não efetuar manutenção dos índices      

#4: Baixo Provisionamento de Equipamento

Mesmo que você utilize todas as boas práticas para a construção do seu banco de dados, nada disso surtirá efeito caso você não tenha recursos suficientes para as estruturas sejam utilizadas com uma folga no servidor, ou seja, é importante a metrificação do tamanho do equipamento ou instância que rodará o banco de dados, entre as principais métricas CPU, Memória, Espaço em Disco. Os erros listados devem ser evitados a qualquer custo:

CPU funcionando mais de 90% constantemente
95% da memória sendo utilizadas
Leitura e escrita (I/O) em disco muito alta

#Conhecimento

A palavra chave para criação de um banco de dados performático é conhecimento.

Um profissional de TI, deve continuar aprendendo e se desenvolvendo para ficar à frente de todos os novos desafios futuros, e através dessas informações poderá aplicar mais práticas relevantes para melhorar a qualidade final de seu trabalho.

A cada novo dia, novas ferramentas, metodologias e ferramentas são criadas, sendo disponibilizadas para auxiliar na criação de melhores soluções.

Mantenha-se atualizado sempre.

Marcelo Goberto de Azevedo
Arquiteto na GFT Brasil
https://marcelogoberto.blogspot.com/

segunda-feira, 20 de janeiro de 2020

COMPREENDENDO INNER JOIN, LEFT JOIN, RIGHT JOIN e FULL OUTER JOIN




O conceito é bem simples, todos nós aprendemos na escola a teoria dos conjuntos, logo a extração de informação com interseção no SQL é simplesmente gerar um subconjunto do conjunto universo.

Digamos que tenhamos duas tabelas, sendo uma de CLIENTE e outra de PEDIDO, conforme a estrutura abaixo:

CLI_CLIENTE
CLI_N_CODIGO
CLI_C_RAZAO
CLI_C_PAIS
1
Acne Ltda
Brasil
2
Limofer Industria
China
4
Kimber Partner S/A
EUA

PED_PEDIDO
PED_C_CODIGO
PED_CLI_N_CODIGO
PED_D_DATA
PED_N_VALOR
100/2019
1
2019-05-01
300,00
101/2019
1
2019-09-12
550,00
102/2019
4
2019-09-24
1000,00
100/2020
5
2020-01-01
600,00

INNER JOIN

Forma clássica de retorno do subconjunto somente com o que é comum na ligação (ON) entre as tabelas.

SELECT CLI_N_CODIGO, CLI_C_RAZAO, PED_C_CODIGO, PED_D_DATA, PED_N_VALOR
       FROM CLI_CLIENTE
              INNER JOIN PED_PEDIDO
                    ON CLI_N_CODIGO = PED_CLI_N_CODIGO

CLI_N_CODIGO
CLI_C_RAZAO
PED_C_CODIGO
PED_D_DATA
PED_N_VALOR
1
Acne Ltda
100/2019
2019-05-01
300,00
1
Acne Ltda
101/2019
2019-09-12
550,00
4
Kimber Partner S/A
102/2019
2019-09-24
1000,00

LEFT E RIGHT JOIN

Retorna somente a partir da tabela que e direção que está sendo usado, no caso do LEFT (a primeira tabela) e RIGHT (a segunda tabela) do JOIN.

SELECT CLI_N_CODIGO, CLI_C_RAZAO, PED_C_CODIGO, PED_D_DATA, PED_N_VALOR
       FROM CLI_CLIENTE
              LEFT JOIN PED_PEDIDO
                    ON CLI_N_CODIGO = PED_CLI_N_CODIGO

CLI_N_CODIGO
CLI_C_RAZAO
PED_C_CODIGO
PED_D_DATA
PED_N_VALOR
1
Acne Ltda
100/2019
2019-05-01
300,00
1
Acne Ltda
101/2019
2019-09-12
550,00
2
Limofer Industria
NULL
NULL
NULL
4
Kimber Partner S/A
102/2019
2019-09-24
1000,00

SELECT CLI_N_CODIGO, CLI_C_RAZAO, PED_C_CODIGO, PED_D_DATA, PED_N_VALOR
       FROM CLI_CLIENTE
              RIGHT JOIN PED_PEDIDO
                    ON CLI_N_CODIGO = PED_CLI_N_CODIGO

CLI_N_CODIGO
CLI_C_RAZAO
PED_C_CODIGO
PED_D_DATA
PED_N_VALOR
1
Acne Ltda
100/2019
2019-05-01
300,00
1
Acne Ltda
101/2019
2019-09-12
550,00
NULL
NULL
100/2020
2020-01-01
600,00
4
Kimber Partner S/A
102/2019
2019-09-24
1000,00

FULL OUTER JOIN

Retorna todo o conjunto relacionando os dados que existem  entre a ligação (ON) e para os casos que não haja ligação carregados os dados nullos.

 SELECT CLI_N_CODIGO, CLI_C_RAZAO, PED_C_CODIGO, PED_D_DATA, PED_N_VALOR
       FROM CLI_CLIENTE
              FULL OUTER JOIN PED_PEDIDO
                    ON CLI_N_CODIGO = PED_CLI_N_CODIGO

CLI_N_CODIGO
CLI_C_RAZAO
PED_C_CODIGO
PED_D_DATA
PED_N_VALOR
1
Acne Ltda
100/2019
2019-05-01
300,00
1
Acne Ltda
101/2019
2019-09-12
550,00
2
Limofer Industria
NULL
NULL
NULL
4
Kimber Partner S/A
102/2019
2019-09-24
1000,00
NULL
NULL
100/2020
2020-01-01
600,00

Segue um infográfico que ajuda no entendimento de cada tipo de ligação.


Marcelo Goberto de Azevedo
Arquiteto na GFT Brasil
https://marcelogoberto.blogspot.com/