第一个具有参照完整性约束的数据库 - 建议,反馈,错误?

时间:2010-12-03 14:58:03

标签: mysql database database-design rdbms referential-integrity

TARGET_RDBMS: MySQL-5.X-InnoDB(“X”等于当前稳定版本)

背景:使用真正的参照完整性约束构建我的第一个数据库,为了获得反馈,在创建“真正的”DDL之后,我做了一个我认为涵盖“感觉”的抽象“数据库;这只有3个约20个表,都有参照完整性约束;只有我看到缺少的模式是一个复合键表,无论如何都没有现在要转储的数据,所以我只关注第一次迭代。

示例数据/单元测试:我不知道的一件事是如何构建一个样本数据集,它将提供100%覆盖建模的参照完整性 - 并构建“单元测试”围绕该示例数据和此DDL:

示例DLL:

(注意:为了清楚起见,LEGEND和命名标准仅适用于此示例,我从“真实”数据库中抽象出来。列名称本质上是机器人,旨在表达意义和关系如果您对所使用的符号系统有任何建议,请随时发表评论。我愿意接受任何建议。谢谢!)

CREATE DATABASE sampleDB;

use sampleDB;

# ###############
# LEGEND
# - sID = surrogate key
# - nID = natural key
# - cID = common/shared across tables, but NOT unique/natural-key
# - PK = Primary Key
# - FK = Foreign Key
# - data01 = Sample data (non-key,not-shared-across-tables)
# - data02 = Sample data NOT NULL (non-key,not-shared-across-tables)
#
# - uID = user defined unique/natural key (NOTE: not used)

# ###############
# Behavior
# - create_timestamp (NOT NULL, updated on record creation, NOT update)
# - update_timestamp (NOT NULL, updated on record creation AND updates)

CREATE TABLE `TABLE_01` (
  `TABLE_01_sID_PK` MEDIUMINT NOT NULL AUTO_INCREMENT,
  `TABLE_01_cID` int(8) NOT NULL,
  `TABLE_01_data01` varchar(128) default NULL,
  `TABLE_01_data02`  varchar(128) default NULL,
  `create_timestamp` DATETIME DEFAULT NULL,
  `update_timestamp` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY  (`TABLE_01_sID_PK`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `TABLE_02` (
  `TABLE_02_sID_PK` MEDIUMINT NOT NULL AUTO_INCREMENT,
  `TABLE_02_nID_FK__TABLE_01_sID_PK` int(8) NOT NULL,
  `TABLE_02_cID` int(8) NOT NULL,
  `TABLE_02_data01` varchar(128) default NULL,
  `TABLE_02_data02` varchar(128) NOT NULL,
  `create_timestamp` DATETIME DEFAULT NULL,
  `update_timestamp` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`TABLE_02_sID_PK`),
  FOREIGN KEY (TABLE_02_nID_FK__TABLE_01_sID_PK) REFERENCES TABLE_01(TABLE_01_sID_PK),
  INDEX `TABLE_02_nID_FK__TABLE_01_sID_PK` (`TABLE_02_nID_FK__TABLE_01_sID_PK`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `TABLE_03` (
  `TABLE_03_sID_PK` MEDIUMINT NOT NULL AUTO_INCREMENT,
  `TABLE_03_nID_FK__TABLE_01_sID_PK` int(8) NOT NULL,
  `TABLE_03_nID_FK__TABLE_02_sID_PK` int(8) NOT NULL,
  `TABLE_03_cID` int(8) NOT NULL,
  `TABLE_03_data01` varchar(128) default NULL,
  `TABLE_03_data02` varchar(128) NOT NULL,
  `create_timestamp` DATETIME DEFAULT NULL,
  `update_timestamp` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`TABLE_03_sID_PK`),
  FOREIGN KEY (TABLE_03_nID_FK__TABLE_01_sID_PK) REFERENCES TABLE_01(TABLE_01_sID_PK),
  FOREIGN KEY (TABLE_03_nID_FK__TABLE_02_sID_PK) REFERENCES TABLE_02(TABLE_02_sID_PK),
  INDEX `TABLE_03_nID_FK__TABLE_01_sID_PK` (`TABLE_03_nID_FK__TABLE_01_sID_PK`),
  INDEX `TABLE_03_nID_FK__TABLE_02_sID_PK` (`TABLE_03_nID_FK__TABLE_02_sID_PK`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

SHOW TABLES;

# DROP DATABASE `sampleDB`;

# #######################
# View table definition
# DESC inserttablename;

# #######################
# View table create statement
# SHOW CREATE TABLE example;

问题:

欢迎任何和所有关于缺少,错误或“更好”的方法来做这个数据库构建的反馈。如果您有疑问,请发表评论 - 我会尽快回复。再次,谢谢〜!

更新(1):

刚刚向PK添加了“MEDIUMINT NOT NULL AUTO_INCREMENT” - 不知道我是怎么离开它的。

1 个答案:

答案 0 :(得分:3)

首先,我想为您定义标准而喝彩。未来对你有多大帮助是无止境的。

话虽如此,我的一些非常主观的意见:

我不喜欢在名称中嵌入类型信息,例如“TABLE_PERSON”或“PERSON_T”,因为第二次用视图替换表时会变得混乱。此时你可以搜索并用“PERSON_VW”代替“PERSON_T”,但它有点遗漏了这一点:) 列也是如此(虽然我在你的例子中看不到这一点)。想想从“数字”变为“varchar”的“n_is_dead”列。

表中是否存在未创建的行(create_timestamp)?如果列真的不能为null,则将列声明为NOT NULL。实际上,我开始在我的大多数列上都使用NOT NULL,因为这让我更加难以理解数据的本质。

我喜欢将主键列命名为ID之外的其他内容。例如

company(company_id, etc)
person(person_id, company_id, firstname etc)

我听说有些人在O / R地图制作器方面遇到问题,他们希望你随时都有一个名为“ID”的主键,但我不知道最近是否改变这种情况是否仍然存在。

我不清楚你是否打算在列名中嵌入(s,n,c)来表明它们是代理,自然或共同密钥。但我也不认为这是个好主意。我觉得这会“揭示”一些不适合逻辑模型的实现细节。

看起来您正在列名中公开/嵌入外键关系。我从来没有想过这个,但我想你会对此深感遗憾。如果不仅因为它使列名无法忍受uggly:)

为索引选择名称时。我唯一一次后悔命名一个索引就是当我查看执行计划并看到正在使用的“index_01”时。我一直希望我已将列名放在索引中,以使其在xplan中可见。我不知道索引名称的限制,但我总是遇到Oracle的限制。因此,尝试为如何缩写表名提出一些规则。列名在这里很重要。

关于混合案例。我总是(没有例外)使用ALL_UPPER_CASE或all_lower_case。原因是在过去,当他们以不同方式处理案例时,我在数据库之间迁移查询时被烧毁了。最近,我使用all_lower_case,因为我们的编辑器的典型字体使得在小写字母中比在大写字母中更容易发现拼写错误。当我在某些事情上失败时,看起来好像编辑器正在向我展示;)