Portanto, meu chefe e eu estamos em desacordo sobre a melhor forma de projetar nosso banco de dados para armazenar dados diversos de determinados clientes.
Basicamente, temos um monte de tabelas em algum formato semelhante a este (em pseudo-código para simplificar):
TABLE [dbo].[SalesData]
[CampaignID] int IDENTITY(1, 1) NOT NULL, (This is the PK)
[CustomerID] int NULL,
[Calls] float NULL,
[Responses] float NULL,
[Sales] float NULL,
[Revenue] money NULL,
[Cost] money NULL,
[WebSales] float NULL,
[Channel] nvarchar(20) NULL
O que acontece é que, à medida que ganhamos clientes, às vezes somos forçados a adicionar algum tipo de coleta de dados personalizada para cada um. Para esta tabela, tudo é usado por cada cliente (temos cerca de 20), exceto WebSales e Channel, que é usado apenas por 1 cliente. Outro cliente deseja que alguns novos dados sejam rastreados e, portanto, precisamos adicionar mais colunas ou separar esses dados em uma tabela relacionada e iniciar um sistema de supertipo-subtipo.
O que eu quero fazer também é separar WebSales e Channel e adicionar uma tabela para cada cliente desta maneira:
TABLE [dbo].[SalesData_Client1]
[CampaignID] int NOT NULL, (PK and FK to the SalesData table)
[WebSales] float NOT NULL DEFAULT 0,
[Channel] nvarchar(20) NOT NULL DEFAULT ''
ADD CONSTRAINT [CK__SalesData_Client1__CustomersCampaignID]
CHECK (dbo.CustomerOfCampaignID(CampaignID) = Client1)
Em seguida, descartaria essas colunas da tabela original e transformaria o segundo cliente em uma tabela como esta também. O chefe acha que isso significa que teremos que adicionar muitas tabelas à medida que ganhamos clientes e quer adicionar mais colunas. Ele prefere alterar a tabela SalesData assim:
TABLE [dbo].[SalesData]
[CampaignID] int IDENTITY(1, 1) NOT NULL, (This is the PK)
[CustomerID] int NULL,
[Calls] float NULL,
[Responses] float NULL,
[Sales] float NULL,
[Revenue] money NULL,
[Cost] money NULL,
[Unknown] char(10) NULL,
[Misc1] float NULL,
[Misc2] nvarchar(20) NULL
[Misc3] int NULL,
[Misc4] int NULL
[Misc5] int NULL
Onde as colunas "Misc" podem ser usadas para qualquer coisa, e então os programadores podem "simplesmente descobrir com base no cliente". Eu sei as razões pelas quais você não deveria fazer dessa maneira, isso viola a normalização e tornará o desempenho cada vez pior à medida que adicionamos colunas, etc. Mas ele continua voltando com "É muito mais simples" e não gosta disso cada novo cliente pode significar outra nova mesa. Ele também ressalta que colunas mais recentes, como Websales, podem ser usadas por mais de 1 cliente eventualmente, e será uma grande dor de cabeça tê-las em várias tabelas de subtipos ou movê-las de várias tabelas de subtipos para a tabela principal, se precisarmos sempre quis fazer isso.
Existe um método melhor do que a solução de supertipo/subtipo que eu criei para facilitar as coisas para ele e para os programadores? Uma observação importante é que os dados de cada cliente estão basicamente em seu próprio universo e NUNCA se misturarão. Sei que é meio subjetivo e a resposta dependerá de quantas colunas "Misc" estamos esperando seriamente. A razão pela qual quero seguir a rota do subtipo é porque o próximo cliente pode exigir 5 novas colunas bigint, pelo que sei.
Para ser verdadeiramente flexível, você poderia seguir a rota Entidade-Atributo-Valor , mas isso provavelmente seria um exagero para isso e há muitos que argumentariam que o EAV é um antipadrão terrível.
Acho que as tabelas específicas do cliente podem ser o melhor caminho a seguir se você acha que eventualmente acabará com dezenas e dezenas de colunas específicas do cliente em uma única tabela.
Esta provavelmente não é a opção certa no seu caso, mas vou jogá-la fora de qualquer maneira. Você pode ter uma segunda tabela com um
CampaignID
PK e todos os vários campos específicos do cliente. Poderia acabar muito amplo, mas você manteria a segurança de tipo e nomes sensatos, e sua tabela principal permaneceria limpa. Como você armazenaria apenas uma linha para clientes com campos personalizados, o armazenamento deve ser razoável.Você acabaria com colunas esparsas, mas existem algumas ferramentas para manter essas tabelas rápidas e compactas. Você pode optar por prefixar os campos personalizados com os nomes dos clientes, diminuindo a ambiguidade, mas evitando que você reutilize um campo para vários clientes.
Isso é semelhante ao conceito de data warehouse de uma "dimensão de lixo", que contém todos os bits diversos de dados que você não deseja sobrecarregar sua tabela de fatos, mas que não classificam como tendo tabelas de dimensões próprias.
Para ser claro: não estou realmente recomendando esta opção no seu caso; qualquer solução que envolva DDL rotineiramente não é, IMHO, uma solução. Eu recomendo o padrão EAV fornecido pela Frustrated.