Introdução
Para que esta questão seja útil para futuros leitores, usarei o modelo de dados genérico para ilustrar os problemas que enfrento.
Nosso modelo de dados consiste em duas entidades, que serão rotuladas como A
e B
. Para manter as coisas simples, todos os seus atributos serão do int
tipo.
A entidade A
possui os seguintes atributos: D
e X
; A entidade B
possui os seguintes atributos: D
e Y
;
Problema
Como ambas as entidades compartilham atributos comuns D
, decidi aplicar o design de tipo/subtipo .
Não tenho certeza se minha implementação está correta, portanto, estou pedindo aqui uma revisão do design.
Minha Implementação
-- lookup table for discriminator column
CREATE TABLE ClassType
(
ClassTypeID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
Class_Description VARCHAR(50) NOT NULL
);
-- inserting types A and B from our example
INSERT INTO ClassType (Class_Description)
VALUES ('A'), ('B');
-- creating base class table
CREATE TABLE BaseClass
(
BaseClass_ID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
ClassTypeID INT NOT NULL, -- FK to Type
D int
);
ALTER TABLE BaseClass
ADD CONSTRAINT [FK_BaseClass_ClassType]
FOREIGN KEY (ClassTypeID)
REFERENCES ClassType (ClassTypeID);
-- we need this constraint in order for foreign keys in subclasses to work
ALTER TABLE BaseClass
ADD CONSTRAINT [FK_AltKey]
UNIQUE (BaseClass_ID, ClassTypeID);
-- creating subclasses:
CREATE TABLE SubclassA
(
BaseClass_ID INT NOT NULL PRIMARY KEY,
X int,
ClassTypeID AS 1 PERSISTED -- calculated field, ensures integrity
);
ALTER TABLE SubclassA
ADD CONSTRAINT [FK_SubclassA_BaseClass]
FOREIGN KEY (BaseClass_ID, ClassTypeID)
REFERENCES BaseClass (BaseClass_ID, ClassTypeID);
CREATE TABLE SubclassB
(
BaseClass_ID INT NOT NULL PRIMARY KEY,
Y int,
ClassTypeID AS 2 PERSISTED -- calculated field, ensures integrity
);
ALTER TABLE SubclassB
ADD CONSTRAINT [FK_SubclassB_BaseClass]
FOREIGN KEY (BaseClass_ID, ClassTypeID)
REFERENCES BaseClass (BaseClass_ID, ClassTypeID);
Esta é a aparência do diagrama de banco de dados no SQL Server 2012:
Perguntas
- Cometi algum erro na minha implementação?
- Além de calcular e persistir o tipo de classe (em tabelas de subclasse), há mais alguma coisa que eu possa fazer para evitar erros durante
INSERT/UPDATE/DELETE
?
Sim, o design parece ótimo. Notas menores:
Você poderia usar
TINYINT
, em vez deINT
for theClassTypeID
. Ou mesmoCHAR(1)
e have'A'
e'B'
em vez de1
e2
. 1 byte em vez de 4 significa que você está salvando 3 bytes em cada linha , em todas as 3 tabelas e em cada índice que incluiClassTypeID
- o que seria cada índice nessas tabelas, se fizerClassTypeID
parte da chave agrupada.Os atributos das tabelas base e subtipo podem ser
NOT NULL
. Não vejo por que você os deseja anuláveis, com este design.Pode ser melhor (mas precisa de testes completos) se você tiver a
UNIQUE
restrição da tabela base e as 2 chaves estrangeiras que a referenciam definidas com a ordem reversa(ClassTypeID, BaseClass_ID)
. Isso é mais uma sugestão de indexação/desenho físico, não altera o desenho lógico. Eu também experimentaria ter a chave agrupada na tabela base usando essa ordem.