Cuidado com flags!!

You are able to see this post in english too.

Olá!

O primeiro artigo do ano é sobre modelagem de dados.

Algo que me incomoda há muitos anos em qualquer modelagem de dados são atributos que funcionam como indicadores (ou flags) em tabelas.

Pense duas ou três vezes antes de criá-las pois na maioria dos casos, são desnecessárias. E porquê? Criamos flags para sinalizar a situação de um registro numa tabela, que pode ser muitas vezes verificada em outros atributos, gerando situações de dicotomia (bem problemáticas, por sinal). Vamos aos exemplos:

mysql> SELECT * FROM tb_pedidos LIMIT 5;
+------------ ... +--------------+------------ ... +----------------+
| cod_pedido  ... | metodo_envio | data_envio  ... | pedido_enviado |
+------------ ... +--------------+------------ ... +----------------+
| 986565      ... | 1            | 2010-11-18  ... | S              |
| 659813      ... | NULL         | NULL        ... | N              |
| 986542      ... | 2            | 2010-11-13  ... | S              |
| 321598      ... | 1            | 2010-01-14  ... | S              |
| 112982      ... | NULL         | NULL        ... | N              |
+------------ ... +--------------+------------ ... +----------------+
5 rows in set (0.00 sec)
mysql>

Acima vemos algo bem comum: um flag para indicar algo que uma outra tupla já indica. Além de redundante, isso pode facilmente quebrar a integridade dos dados. Um erro de código ou um mero esquecimento no momento de um insert/update pode resultar na situação abaixo:

mysql> SELECT * FROM tb_pedidos LIMIT 5;
+------------ ... +--------------+------------ ... +----------------+
| cod_pedido  ... | metodo_envio | data_envio  ... | pedido_enviado |
+------------ ... +--------------+------------ ... +----------------+
| 986565      ... | 1            | 2010-11-18  ... | S              |
| 659813      ... | NULL         | NULL        ... | S              |
| 986542      ... | 2            | 2010-11-13  ... | S              |
| 321598      ... | 1            | 2010-01-14  ... | S              |
| 112982      ... | NULL         | NULL        ... | N              |
+------------ ... +--------------+------------ ... +----------------+
5 rows in set (0.00 sec)
mysql>

Ou ainda:

mysql> SELECT * FROM tb_pedidos LIMIT 5;
+------------ ... +--------------+------------ ... +----------------+
| cod_pedido  ... | metodo_envio | data_envio  ... | pedido_enviado |
+------------ ... +--------------+------------ ... +----------------+
| 986565      ... | 1            | 2010-11-18  ... | S              |
| 659813      ... | 1            | 2010-05-12  ... | N              |
| 986542      ... | 2            | 2010-11-13  ... | S              |
| 321598      ... | 1            | 2010-01-14  ... | S              |
| 112982      ... | NULL         | NULL        ... | N              |
+------------ ... +--------------+------------ ... +----------------+
5 rows in set (0.00 sec)
mysql>

Como proceder para tratar este tipo de caso? A resposta é analisar cada flag conforme abaixo:

  • Verifique cuidadosamente cada uma delas. Há outro atributo (ou um conjunto deles, mesmo em outras tabelas) que seja capaz de mostrar a situação requerida? Se sim, talvez esta flag seja inútil, e você pode realizar uma das ações abaixo:
    • Crie-a como campo calculado na tabela em questão;
    • Crie views, e nelas crie a flag como campo calculado;
    • Em último caso, use triggers para alimentar as flags com base no atributo/tupla que pode mostrar a situação.

Claro, há situações em que a flag é necessária, e neste caso sou a favor delas (vide atributos “sexo” e “registro_ativo” abaixo):

mysql> SELECT * FROM tb_pessoas LIMIT 5;
+------------ ... +------ ... +------------+ ... +-----------------+ ...
| nome_pessoa ... | sexo  ... | data_cad   | ... | registro_ativo  | ...
+------------ ... +------ ... +------------+ ... +-----------------+ ...
| Carlos      ... | M     ... | 2006-01-18 | ... | S               | ...
| Sandro      ... | M     ... | 2005-01-12 | ... | S               | ...
| Henrique    ... | M     ... | 2008-02-13 | ... | S               | ...
| Luiza       ... | F     ... | 2006-01-14 | ... | S               | ...
| Antonio     ... | M     ... | 2008-01-14 | ... | N               | ...
+------------ ... +------ ... +------------+ ... +-----------------+ ...
5 rows in set (0.00 sec)
mysql>

Uma boa dica seria fazer a seguinte pergunta a si mesmo antes de criar um atributo indicador/flag: “Este atributo serve para indicar uma situação cujo estado pode alterar durante a vida do registro?” Se a resposta tende para SIM, então imagine o farol no mínimo, na cor amarela. Então vá com cuidado e analise se pode, ao invés de criar mais um atributo físico, criar um campo calculado, uma view ou uma trigger para alimentá-lo de forma automática.

Concorda/Discorda/Algo a acrescentar? Comente!!

Até! 😉

About Adriano Laranjeira

Software engineer & developer See more at http://about.me/arglbr
This entry was posted in Português and tagged , , , . Bookmark the permalink.

5 Responses to Cuidado com flags!!

  1. Pingback: Adriano Laranjeira » Blog Archive » Beware with flags!!

  2. Ricardo Johannsen says:

    Boas dicas, em um sistema que estou desenvolvendo estou utilizando uma flag em uma das minhas tabelas para representar o status do registro(A- aberto ,R -em revisão,F -finalizado) , a pergunta é, em um select que eu deseje trazer os resultados de acordo com os status oque é “melhor/mais eficiente/menos ruim” utilizar as tais flags ou ter uma tabela status e fazer join, qual é mais custoso para o banco?

    Like

    • Adriano says:

      Olá Ricardo, obrigado pelo acesso 🙂

      Pelas flags que está criando, acredito ser melhor mantê-las sem join ou tabelas de status. No entanto você ganha o custo de manter o significado de cada flag bem documentado em algum lugar no código ou no script do banco. A consistência você consegue melhora-la atribuindo estas flags via trigger, o que lhe torna independente de um programador de conhece-las.

      Até!!
      Adriano Laranjeira
      http://about.me/arglbr

      Like

  3. Ricardo Johannsen says:

    Olá, manti apenas as flags mesmo, ficou bem legal como uso Enumerations do Java para definir as flags, o código ficou bem documentado, com Enum fica bem claro oque cada tag representa. Agora uma outra situação:
    Temos um sistema de almoxarifado, a cada entrada ou saida de produtos, é inserida na tabela de movimentos, que foi modelada assim :
    movimento_id,produto_id,quantidade,tipo_movimento,compra_id,requisicao_id
    Se foi uma entrada ele seta a qtd de produto que entrou, seta o tipo como “E”, seta o compra_id com o id da compra e deixa a requisicao_id nula, a mesma coisa acontece na saída de produtos só que quem fica nulo agora é o compra_id, e o requisicao_id é preenchido com o id da requisição que gerou o movimento ou seja a cada movimentação eu vou ter ou o compra_id, ou o requisicao_id nulo dependendo do tipo de movimentação, gostaria de saber se isso é uma má prática, se é esse artifício é válido ou não e se pode acarretar algum problema de inconsistência ou desperdício de espaço em disco.
    Atenciosamente.

    Like

  4. Adriano says:

    Olá Ricardo!

    Bom saber que está feliz com os resultados. O importante é manter as coisas sem repetições e facilmente identificáveis no código.

    Sobre a situação apresentada, a flag só faria sentido se tanto “compra_id” e “requisicao_id” fossem gravados no mesmo atributo – o que não acontece em sua modelagem. Por isso, acredito sim que da forma como está o atributo “tipo_movimento” é desnecessário num primeiro momento e é um fator de risco para gerar inconsistência nos dados. O refactoring pode ir em três caminhos:
    a) Utilizar um único atributo para o ID da requisição/compra e manter o atributo tipo_movimento;
    b) Remover o atributo tipo_movimento, confiando apenas nos atributos ID’s;
    c) Separar estas movimentações em tabelas diferentes.

    Lembre-se que para decidir isso é importante observar também a quantidade de transações R/W nesta tabela, além do tamanho dela… mas aí deixo pra você analisar e escolher o que for melhor para o seu sistema. Lembre-se que o mais importante é manter o sistema simples o suficiente para sofrer eventuais manutenções.

    Abs & boa sorte!
    Adriano Laranjeira
    https://about.me/arglbr

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s