Para melhor visualização, recomendo resolução de no mínimo 1280 x 800 e navegador Mozilla Firefox


quinta-feira, 4 de junho de 2009

Dúvidas sobre modelagem de dados ...

Por Eduardo Legatti

Olá,

Recentemente recebi de um colega, uma dúvida sobre modelagem de dados e resolvi então compartilhar aqui.

Cenário:

Possuo um cadastro de clientes que usa o serviço de hospedagem de sites e um outro cadastro que utiliza o serviço de registro de domínios. A grande questão é como representar isso, os casos são os seguintes:


  • Um cliente pode ter somente o serviço de hospedagem de sites, logo, todos os seus dados estariam na tabela de hospedagem.
  • Um cliente pode ter somente o serviço de registro de domínios, logo, todos os seus dados estariam na tabela de registro de domínios.
  • Um cliente pode ter ambos os serviços, logo, teria dados nas 2 tabelas, mas, esses dados poderiam ser os mesmos, como também não poderiam.


Detalhe: Essa estrutura precisaria ser preparada para num futuro próximo aumentar os serviços, ou seja, além de hospedagem e domínios, possuir outros, loja virtual, etc.


Enfim, imaginei uma terceira tabela para controlar isso, mandei um esboço em anexo mas estou receoso devido ao fato de com isso existirem muitas chaves estrangeiras nulas e a aplicação precisaria descobrir em qual tabela estariam os dados do cliente.


Solução:

Bem, em relação ao último parágrafo do texto acima, posso dizer que chaves estrangeiras nulas não são problema algum. Imagine que eu tenha uma tabela de clientes onde a mesma possua uma coluna (id_servico) que armazene códigos de serviços, e que a mesma referencie a tabela de serviços.


Se pode haver clientes que não prestam nenhum serviço, então poderiam existir vários clientes onde a coluna id_serviço estaria NULA.


Não se pode confundir chave estrangeira com chave primária. Chave primária é obrigatória, mas chave estrangeira pode ou não ser obrigatória e isso vai depender da regra de negócio em questão.


Voltando ao cenário proposto, isso está me parecendo um relacionamento simples onde "Um Cliente pode prestar vários serviços" e "Um serviço pode ser prestado por vários clientes".

Se você quer uma estrutura flexível e, já pensando em um futuro próximo, permitir o registro de mais serviços, então criar tabelas específicas para armazenar cada serviço seria praticamente inviável e sem sentido. Acredito que com apenas 3 tabelas o seu problema seria solucionado, mas para complicar um pouco avalie se uma quarta tabela seria útil para você. Então, neste caso, avalie a solução abaixo:

1) criar uma tabela de clientes
2) criar uma tabela de serviços
3) criar uma tabela que armazenará os serviços que cada cliente poderá prestar

4) criar uma tabela com colunas adicionais que registrará todos os serviços de todos os clientes


Portanto, tome como exemplo os dados abaixo de acordo com o modelo acima proposto:


=======
CLIENTE
=======

ID_CLIENTE NOME_CLIENTE
---------- ------------
         1 Cliente A
         2 Cliente B
         3 Cliente C


=======
SERVICO
=======

ID_SERVICO NOME_SERVICO
---------- -------------------
         1 Hospedagem de sites 
         2 Registro de domínio
         3 Loja Virtual
         4 Outro, etc...

Abaixo irei definir quais serviços cada cliente poderá prestar:

===============
CLIENTE_SERVICO
===============

ID_CLIENTE ID_SERVICO
---------- ----------
         1          1
         1          2
         2          3
         3          2
         4          1

Para finalizar, a tabela REGISTRO abaixo armazenaria todos os serviços de todos os clientes sendo que a coluna ID_REGISTRO seria um seqüencial.


========
REGISTRO
========

ID_REGISTRO ID_CLIENTE ID_SERVICO ENDERECO_WEB ETC...
----------- ---------- ---------- ------------ ------
          1          1          1 http:// .... ... 
          2          1          2 http:// .... ...
          3          2          3 http:// .... ...
          4          3          2 http:// .... ...
          5          4          1 http:// .... ...


Como você viu acima, a tabela REGISTRO, a princípio, parece ser redundante no modelo pois faz o mesmo papel da tabela CLIENTE_SERVICO mas, neste caso, você poderia armazenar mais registros do mesmo serviço para o mesmo cliente. Por outro lado, bastaria também fazer um relacionamento não identificado na tabela CLIENTE_SERVICO onde as colunas ID_CLIENTE e ID_SERVICO seriam apenas chaves estrangeiras, e não chaves primárias.


Dependendo do caso, você poderá trabalhar somente com a tabela CLIENTE_SERVICO deixando a tabela REGISTRO fora do modelo, ou seja, a tabela REGISTRO seria opcional.

No mais, isso realmente vai depender das regras de negócios envolvidas na sua aplicação de forma a atingir os requisitos necessários.


Enfim, de acordo com o modelo e na minha visão, a tabela CLIENTE_SERVICO teria apenas o papel de armazenar de forma parametrizável o que cada cliente poderia fornecer, obedecendo assim, o requisito na qual você diz que "Um cliente poderá ter somente o serviço X ou Y ou ambos ..."



5 comentários:

Priscila disse...

Parabéns, pelo o artigo.
Estou com duvida, será que você pode me ajudar?
Qual é a melhor forma visando a performance do sistema, de criar tabelas sumarizadas?

Eduardo Legatti disse...

Olá Priscila,

Uma tabela sumarizada tem como objetivo armazenar dados provenientes de outras tabelas em forma de agrupamento ou sumarização. Essas tabelas podem ser temporárias ou não.

Já criei muitas tabelas sumarizadas que eram populadas através de procedimentos armazenados, triggers, etc. O objetivo simplesmente era melhorar a performance de uma rotina ou relatório no sistema. Haviam tabelas sumarizadas na qual os dados eram apenas temporários, ou seja, existiam apenas durante a execução de uma rotina ou relatório. Após a execução da rotina a tabela era truncada ou até mesmo dropada. A dica que eu dou é a seguinte: Tente modelar a tabela sumarizada de acordo com as informações que precisam ser mostradas ao usuário final. Depois você poderá analisar os ajustes que precisam ser realizados, como criação de índices por exemplo.

Abraços

Legatti

Priscila disse...

Muito obrigada Legatti,
Outra duvida:
Esta tabela sumarizada você criava relacionamento (FK)quando precisasse? Ou deixava ela sozinha? Qual é o mais performatico?

Eduardo Legatti disse...

Olá Priscila,

Quando as tabelas eram temporárias, ou seja, criadas apenas durante a execução de alguma rotina, eu não criava FKs, apenas índices. Se as as tabelas eram persistentes, então eu criava as FKs. As FKs são importantes não só para a documentação do modelo de dados na qual se evidenciam os relacionamentos entre as tabelas, mas também para ajudar o otimizador do banco de dados a encontrar o plano de execução mais apropriado para uma determinada instrução SQL. Para cada INSERT efetuado em uma tabela filha, o valor da coluna FK será verificado na tabela pai correspondente. Da mesma forma que índices de tabelas podem impactar negativamente a performandce de instruções INSERT, as FKs podem causar um pouco delentidão caso a tabela pai for muito grande. Às vezes esse impacto não é nem percebido. Tudo depende da volumetria e tamanho das tabelas envolvidas. Enfim, somente com testes e simulações com carga de dados que você irá conseguir decidir se cria ou não as FKs. No mais, como regra, sempre crie FKs e sempre que possível crie índices nas colunas FKs.

Abraços e até mais ...

Legatti

Priscila disse...

Muito obrigada Legatti, você me ajudou muito.
Parabéns pela a explicação, eu sempre acompanho o seu blog.

Abraços.
Priscila.

Postagens populares