2

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

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

示例数据/单元测试:我不知道的一件事是如何构建一个示例数据集,该数据集将提供 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”——不知道我是怎么把它关掉的。

4

1 回答 1

3

首先,我要为您定义标准而鼓掌。未来对你的帮助是无穷无尽的。

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

我不喜欢在名称中嵌入类型信息,例如“TABLE_PERSON”或“PERSON_T”,因为当您将表替换为视图时,它会变得令人困惑。此时,您当然可以搜索“PERSON_T”并将其替换为“PERSON_VW”,但这有点忽略了这一点:)列也是如此(尽管我在您的示例中看不到这一点)。想想从数字更改为 varchar 的“n_is_dead”列。

表中是否可以存在一行而不被创建(create_timestamp)?如果列确实不能为空,则将列声明为 NOT NULL。事实上,我开始在我的大多数列上都使用 NOT NULL,因为它让我更加思考数据的性质。

我喜欢将主键列命名为 ID 以外的名称。例如

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

我听说有些人在使用 O/R 映射器时遇到问题,希望您始终拥有名为“ID”的主键,但我不知道这是否仍然适用,如果最近发生了变化。

我不清楚您是否打算在列名中嵌入 (s,n,c) 以指示它们是代理键、自然键还是公用键。但我也不认为这是一个好主意。我觉得这会“揭示”一些不适合逻辑模型的实现细节。

看起来您在列名中公开/嵌入外键关系。我从来没有想过这一点,但我想你会深深地后悔这一点。如果不仅仅是因为它使列名难以忍受:)

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

关于混合情况。我总是(没有例外)使用 ALL_UPPER_CASE 或 all_lower_case。原因是过去在数据库之间迁移查询时,当它们以不同的方式处理大小写时,我已经被烧毁了。最近,我使用 all_lower_case,因为我们的编辑器的典型字体使得发现小写的拼写错误比大写的更容易。当我在事情上失败时,编辑似乎并没有对我大喊大叫;)

于 2010-12-03T15:50:47.640 回答