我的类型/子类型设计模式(对于互斥子类)的实现是否正确?

Alw*_*uff 7 database-design sql-server sql-server-2012 subtypes

介绍

为了让这个问题对未来的读者有用,我将使用通用数据模型来说明我面临的问题。

我们的数据模型由两个实体组成,它们应标记为AB。为了简单起见,它们的所有属性都将是int类型。

实体A具有以下属性:DX;实体B具有以下属性:DY

问题

由于两个实体共享共同的属性D,我决定应用类型/子类型设计。

我不确定我的实现是否正确,因此我在这里要求进行设计审查。

我的实现

-- 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);
Run Code Online (Sandbox Code Playgroud)

这是数据库图表在 SQL Server 2012 中的外观:

数据库图

问题

  • 我在实施过程中是否犯了任何错误?
  • 除了计算和持久化类类型(在子类表中)之外,还有什么我可以做的来防止错误INSERT/UPDATE/DELETE

ype*_*eᵀᴹ 6

是的,设计看起来很棒。小注:

  • 您可以使用TINYINT, 而不是INTfor ClassTypeID。或者甚至CHAR(1)and have 'A'and'B'而不是1and 2。1 个字节而不是 4个字节意味着您在每行、所有 3 个表和包含的每个索引中节省3 个字节ClassTypeID- 如果ClassTypeID是聚集键的一部分,则这些表上的每个索引都将节省。

  • 基表和子类型表的属性都可以是NOT NULL. 我不明白为什么你会希望它们可以为空,使用这种设计。

  • 如果您同时UNIQUE拥有基表的约束和以相反顺序定义的引用它的 2 个外键,它可能会更好(但需要彻底测试)(ClassTypeID, BaseClass_ID)。这更像是一个索引/物理设计建议,它不会改变逻辑设计。我也会尝试使用此顺序在基表中包含聚集键。

  • TINYINT 也是 1 个字节,但 CHAR(1) 在查看数据时更具可读性。尽管使用 char 而不是整数列(因为必须考虑排序规则/字符集),但开销很小。 (4认同)