MySQL 表設計


0、這篇博客中一部分內容是Deolin的個人觀點和習慣。

 

1、把SET remove_time = '1970-01-01 00:00:00' 稱為“移除”(remove),

把DELETE FROM table 稱為“擦除”(expunge),

至於“刪除”(delete)、“取消”(cancel),則更像個業務層而不是持久層的概念。

 

2、數據表可以分為信息表,關聯表,字典表。

 

3、信息表反映的是數據信息,“數據為王”主要指的就是這類表里的數據。

信息表應該有以下字段

id int 這條數據的主鍵,默認長度,無符號,自增,前位補零。由於remove_time的存在,所以業務上的字段做主鍵便不再合適,因為新插入的數據很有可能與被移除的數據發生主鍵重復,所以需要一個毫無業務意義的主鍵

insert_time datetime 這條數據第一次執行insert文的時間,不能為空。

update_time datetime 這條數據每次執行update文的時間,可以為空(如果從為被update過,那就應該是空的)。

remove_time datetime 這條數據執行remove文的時間,可以為空,這個字段有值則代表這條數據被刪了,

由於信息表里的數據往往比較重要,所以應該禁止擦除,使用移除。而“有remove_time字段”和“使用移除”兩件事情應該同時出現,或同時不出現

 

信息表可以有以下字段,但不是“應該有”

insert_id int 插入這條數據的業務上的插入者id,代表的是某一個信息表的主鍵(user表之類的)。

insert_table varchar(64) 如果業務上不只一類插入者,那么需要指定是那個信息表。長度定為64,因為表名最長64個字符。

update_id int 與insert_id同理。

update_table varchar(64) 與insert_table同理。

remove_id int 與insert_id同理。

remove_table varchar(64) 與insert_table同理。

 

如果是整個項目在業務上沒有登錄行為,或是管理員在db上插入/修改的,那么些字段只能為空了,這也是這些字段不算“應該有”的原因了。

 

一個信息表的示例可能是這樣的

CREATE TABLE `person` (
  `id` int(11) unsigned zerofill NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `sex` tinyint(1) DEFAULT NULL,
  `birthday` date DEFAULT NULL,
  `father_age` int(3) DEFAULT NULL, #這個字段可能非常奇怪,但Deolin只是希望能在示例里有至少一個int字段,並且最好不是age(age跟birthday一起出現的話顯得更加奇怪)
  `tuition` decimal(8,2) DEFAULT NULL,
  `payment_time` datetime DEFAULT NULL,
  `vip_flag` tinyint(1) DEFAULT NULL,
  `insert_time` datetime NOT NULL,
  `update_time` datetime DEFAULT NULL,
  `remove_time` datetime DEFAULT NULL
  PRIMARY KEY (`id`)
)

 

4、關聯表反映的是兩張信息表之間多對多的關系,例如學生表與課程表之間的關系

除了主鍵,關聯表應該有像信息表那樣的基礎字段。

至於主鍵,它的設計有兩種方式

第一種

放棄主鍵id,而是使用被關聯表各自的id作為雙主鍵(如student_id, lesson_id),

這種方式優點是直觀,一眼就能看出是關聯表,而且關聯關系絕對不會重復。

有個缺點,remove_time和移除操作不能有了,因為會發生主鍵重復,所以只能擦除。

 

第二種

使用主鍵id,優缺點與第一種方式正好相反。

主要適用於兩種場合,一是整個項目有比較強的數據挖掘和分析目地的,即便是關聯關系也要保留下來,

二是關聯關系產生時,會出現一些業務字段(如學生選的課,會有成績,那么成績字段不應該放在student或lesson中,而是應該放在關聯表里)

 

5、字典表反映的是為項目本身提供的各種數據,是對項目擴展性的補充,

(如JSP中option標簽的每一個value屬性,如某個表'kind'之類字段的值解釋,如一些配置屬性),數據量不會很大,

基本上,數據是開發人員錄入,項目不會對它有增、改、移除、擦除操作,只有查詢操作,一個不是特別大的項目只需要一張字典表。

一般只有以下字段

key varchar(255) 主鍵,字典的索引

value varchar(255)  字典的值

group varchar(255) 用來表示key屬於那一類,可以為空

sort int 用來表示key在自己所在group的順序,可以為空

disable tinyint(1) 用來表示這條數據是否被失效,不能為空,默認0

 

6、信息表之間一對一的關系,設計成兩張表的id字段一致

例如`person`表示例中,每個人都有“學生”和“子女”兩個不同模塊的屬性,可以將它們分別抽取出來

CREATE TABLE `person` (
  `id` int(11) unsigned zerofill NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `sex` tinyint(1) DEFAULT NULL,
  `birthday` date DEFAULT NULL,
  `vip_flag` tinyint(1) DEFAULT NULL,
  `insert_time` datetime NOT NULL,
  `update_time` datetime DEFAULT NULL,
  `remove_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)  #與其他兩張表的id形成邏輯外鍵
)
CREATE TABLE `student` (
  `id` int(11) unsigned zerofill NOT NULL AUTO_INCREMENT,
  `tuition` decimal(8,2) DEFAULT NULL,
  `payment_time` datetime DEFAULT NULL,
  `insert_time` datetime NOT NULL,
  `update_time` datetime DEFAULT NULL,
  `remove_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)  #與其他兩張表的id形成邏輯外鍵
)
CREATE TABLE `child` (
  `id` int(11) unsigned zerofill NOT NULL AUTO_INCREMENT,
  `father_age` int(3) DEFAULT NULL,
  `father_job` int(3) DEFAULT NULL,  
  `mother_age` int(3) DEFAULT NULL,    
  `mother_job` int(3) DEFAULT NULL,  
  `insert_time` datetime NOT NULL,
  `update_time` datetime DEFAULT NULL,
  `remove_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)  #與其他兩張表的id形成邏輯外鍵
)

 

7、信息表之間一對多的關系,在“多”的表中追加一個 `for_表名` 字段(如果其他字段中有單詞for,有時候也會設計成`表名_id`)

例如,一家學校當前有多個學生,一個學生當前只能屬於一個學校

CREATE TABLE `school` (
  `id` int(11) unsigned zerofill NOT NULL AUTO_INCREMENT,
  `address` varchar(200) DEFAULT NULL,
  `insert_time` datetime NOT NULL,
  `update_time` datetime DEFAULT NULL,
  `remove_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
)
CREATE TABLE `student` (
  `id` int(11) unsigned zerofill NOT NULL AUTO_INCREMENT,
  `for_school` int(11) NOT NULL DEFAULT '0',  #與school.id形成邏輯外鍵
  `name` varchar(20) DEFAULT NULL,
  `insert_time` datetime NOT NULL,
  `update_time` datetime DEFAULT NULL,
  `remove_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
)

 

8、關聯表的命名,一般是兩張“多”的表的表名用2鏈接

例如一個學生選擇多門課程,一門課程供多名學生選擇

CREATE TABLE `selectable_lesson` (
  `id` int(11) unsigned zerofill NOT NULL AUTO_INCREMENT,  
  #省略
  PRIMARY KEY (`id`)
)

CREATE TABLE `normal_student` (
  `id` int(11) unsigned zerofill NOT NULL AUTO_INCREMENT,  
  #省略
  PRIMARY KEY (`id`)
)

CREATE TABLE `normal_student2selectable_lesson` (  #意為normal student to selectable lesson
  `id` int(11) unsigned zerofill NOT NULL AUTO_INCREMENT,
  `for_normal_student` int(11) NOT NULL DEFAULT '0',  #與normal_student.id形成邏輯外鍵
  `for_selectable_lesson` int(11) NOT NULL DEFAULT '0',  #與selectable_lesson.id形成邏輯外鍵
  `score` int(3) DEFAULT NULL,
  `insert_time` datetime NOT NULL,
  `update_time` datetime DEFAULT NULL,
  `remove_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
)

 

9、信息表的中字段名中不出現表名,

如不采用user.username,而是采用user.name

 

11、信息表中涉及到“屬於什么類型”、“是哪種分類”概念的字段,用`kind`表示,如user.kind

涉及到以上概念信息表,用諸如`food_type`來表示。

 

10、類型

字符串長度不變的用char(n),

字符串能大致確定范圍的用varchar(n),

字符串范圍超過65532的用text,

年齡之類的字段通常用int(n),

上限不定的個數類字段通常用int默認,即最長11,

更長時用bigint,

日期用date,

日期+時間用datetime,

時間用time,

區分類字段(如“性別”,“直轄市”等)用tiny(1)(並在Java代碼中定義好規約),

是/否類字段用tiny(1),

價格類字段用decimal(8,2),-99,999,999.99 ~ 99,999,999.99,

電話/手機用varchar(20),

`id`用int,`insert_time`和`update_time`和`remove_time`用datetime


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM