数据库表设计(一):字段设计规范和命名规范
一、設計規范
1.1.是否需要自增ID?
數據庫表,一定要有id,而且要用自增id!
有些人喜歡用自定義的,用UUID或者其他七七八八的id,如果在架構設計,代碼比較好的情況下,不會出啥大問題,但是一旦代碼寫的不行,極有可能就造成id重復之類的問題。
自增id另外還有一個好處,就是在數據遷移的時候,分頁查詢通過id來進行分頁,速度會比傳統分頁快很多。
這個字段還是要有的,但是強烈建議不要在刪除行數據,查詢數據,修改數據時使用到該字段,因為該字段的單獨操作會破壞掉數據的隔離性。也就是前面所說的,所有的sql操作,都要帶上租戶id再進行。
自增ID規范
- 則表中的第一個id字段一定是主鍵且為自動增長;
- 建議主鍵是整型,最好是unsigned bigint類型,避免后續需要擴展
- 為主鍵選擇更有意義的名稱,如ID這個名稱太過籠統,表達的信息可能不準確。
1.2是否使用備用字段?
在數據表中,不僅設計了當前所需要的字段,而且還在其中留出幾個字段作為備用。
比方說,設計了一個人員表(Person),其中已經添加了各種必要的字段,包括姓名(Name)、性別(Sex)、出生年月日(birthday)等等。大功告成之后,忽然想到,將來系統中應該還會有很多其它與人相關的內容吧,比方說畢業院校,比方說工作單位等等,盡管現在根本不需要填寫,以后可能還是會用到的吧。拍腦袋一項,那就加入5個varchar2型的字段,分別叫做Text1、Text2……Text5,然后又想,應該還有一些日期型的字段需要備用,就又建立了三個date型的字段,分別起名叫做date1、date2、date3。
【解決方案】
其實上面的這種設計方式就是一種“過度設計”,我們應該做的就是“按需設計”。
因此要禁止在表中建立預留字段,理由如下:
1.無法準確的知道預留字段的類型,所以無法選擇合適的類型。
2.無法準確的知道預留字段中所存儲的內容,預留字段的命名很難做到見名識義
3.后期維護預留字段所要的成本,同增加一個字段所需要的成本是相同的。對預留字段類型的修改,會對表進行鎖定。(修改一個字段的成本,大于新增字段)。
推薦解決辦法是,當需要增加相關的信息的時候:
1.3是否使用外鍵、觸發器和存儲過程?
外鍵、觸發器不要有。 數據的完整性靠程序來保證。
觸發器和存儲過程容易將業務邏輯和DB耦合在一起。
有了外鍵、觸發器,你會發現: 寫代碼不方便。 訂正數據不方便。 遷移數據也麻煩。 總之,你要是堅持用,后續的坑等著你。
雖然不建議使用外鍵約束,但是相關聯的列上一定要建立索引。
1.4.表應該具備哪些字段?
自增ID
id必為主鍵,類型為unsigned bigint、單表時自增、步長為 1。若業務場景需要或未來有分庫分表擴展需求,類型為unsigned bigint,建議采用唯一id設計,如SnowFlake雪花ID算法,請最后考慮UUID。
創建時間&修改時間
創建時間create_time和修改時間update_time這兩個字段,每個表都必須有! 數據類型為datetime。
注意,一定要用數據的時間戳,自動生成。不要通過代碼去操作這兩個字段。推薦使用AOP去自動處理。
有了這兩個字段。你可以追溯到數據的時間點,創建和修改的時間點。極大方便你在某些情況下的排查數據問題。
建議時間精確到毫秒級別,因為在大數據量的情況下,可能一秒有幾十、幾百、上千、上萬的數據新增都是有可能的。那么秒級在這種情況下完全就不夠看了,選擇毫秒級別是一個比較好的選擇。
創建人&修改人
創建人create_by和修改人update_by兩個字段,每個表也都必須有。數據類型為unsigned bigint(關聯用戶id)或varchar(關聯登錄名,確保不變)
還是和前面一個原因,出問題的時候可以追溯起因,否則遇上日志過久無法查看或者其他原因出現未知數據,都不知道數據怎么來的,需要花非常大的代價查看日志、代碼等。
軟刪除
只能邏輯刪除,不能物理刪除,重要!!!
CREATE TABLE `database_name`.`table_name` (`id` bigint(18) UNSIGNED NOT NULL COMMENT '雪花算法id IdGenerate.generateId();',`create_by` varchar(20) DEFAULT NULL COMMENT '創建人',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創建時間',`update_user` varchar(20) DEFAULT NULL COMMENT '修改人',`update_by` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間',`is_deleted` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '邏輯刪除標志0有效,1無效',PRIMARY KEY (`id`) );1.5范式與反范式
盡量遵守第三范式的標準(3NF):表內的每一個值只能被表達一次;表內的每一行都應當被唯一的標示;表內不應該存儲依賴于其他鍵的非鍵信息。
表與表之間的信息,用id進行關聯,盡量不要有冗余的信息數據,否則你需要更新同一份信息的時候,需要更新多個地方。
但是在某些情況下,你確認信息不會經常變動,且該信息確實在兩個表中都有會比較好,那么,放心的去冗余吧。但是注意,數據的更新用上事務。
查多改少的場景,適合用字段冗余。還是上面的例子:訂單詳情的查詢很多,但是商品名稱的修改很少,適合將商品名稱冗余到訂單表中
字段允許適當冗余,以提高查詢性能,但必須考慮數據一致性。冗余字段應遵循以下原則。
1)不是頻繁修改的字段。
2)不是唯一索引的字段。
3)不是varchar超長字段,更不能是text字段。
1.6存儲引擎和國際化
所有表必須使用Innodb存儲引擎,5.6以后的默認引擎,支持事務,行級鎖,更好的恢復性,高并發下性能更好。如無說明,建表時一律采用innodb引擎;
數據庫和表要使用統一的字符集(如:UTF8),統一字符集可以避免由于字符集轉換產生的亂碼,MySQL中的UTF8字符集漢字點3個字節,ASCII碼占用1個字節。
字符集:utf8mb4、排序規則:utf8mb4_general_ci
1.7 關于分庫和分表
當單表行數超過500萬或者單表容量超過2GB時,才推薦分庫分表。
二、命名規范
2.1數據庫表名規范
(1)表名、字段名必須使用小寫字母或數字
MySQL在Windows系統中不區分大小寫,但在Linux系統中默認區分大小寫。
正例:aliyun_admin,level_name 反例:AliyunAdmin,levelName(2)表名不使用復數名詞。
表名應該僅僅表示表里面的實體內容,不應該表示實體數量,對應到DO類名也是單數形式,符合表達習慣。
正例:user,employee 反例:users,employees(3)表的命名最好遵循“業務名稱_表的作用”原則
正例:alipay_task,trade_config 反例:yy_all_live_category、yy_alllive_comment_user。 //說明:去除項目名,統一命名規則,均為”yy_alllive_”開頭即可。(4)表的名稱一般使用名詞或者動賓短語(動賓邏輯順序統一)。
錯誤示例:yy_showfriend、yy_user_getpoints、yy_live_program_get。 //說明:去除項目名,統一命名規則,動賓短語分離且動賓邏輯順序統一。(5)表名盡量要用英文單詞的全拼
不要自己對英文單詞進行縮寫,也不要使用漢語拼音和小眾的英文縮寫。可以使用常見的其意義被大眾熟知的英文縮寫或英文字典中定義的縮寫。
數據庫對象的命名要能做到見名識義,并且最好不要超過32個字符。
表名稱不應該取得太長(一般不超過三個英文單詞)
(6)明細表的名稱為:主表的名稱+字符dtl(detail縮寫)
例如:采購定單的名稱為:po_order,則采購定單的明細表為:po_orderdtl。
(7)臨時庫/表必須以tmp為前綴并以日期為后綴。
(8)備份庫/表必須以bak為前綴并以日期為后綴。
(9)通用表要加前綴“all_”,示例:all_user。
(10)表必須填寫描述信息(使用SQL語句建表時)
(11)一個項目一個數據庫,多個項目慎用同一個數據庫。
2.2數據庫字段命名規范
(1)字段必須填寫描述信息。
(2)當修改字段含義或追加字段表示的狀態時,需要及時更新字段注釋。
(3)多個單詞使用下劃線’_'分隔
采用26個英文字母(區分大小寫)和0-9的自然數(經常不需要)加上下劃線’‘組成,命名簡潔明確,多個單詞用下劃線’'分隔。
反例:username、userid、isfriend、isgood。 //說明:使用下劃線進行分類,提升可讀性,方便管理 //修改為“user_name”、 “user_id”、 “is_friend”、 “is_good”。(4)全部小寫命名,禁止出現大寫。
反例:userID、houseID。 //說明:使用統一規則,修改為“user_id”、“house_id”。(5)禁用保留字,如name、desc、range、match、delayed等。
請參考MySQL官方保留字。
(6)字段名稱一般采用名詞或動賓短語。
名詞示例:user_id、user_name、sex;動賓短語示例:is_friend、is_good。(7)命名字段時要用英文單詞的全拼
不要自己對英文單詞進行縮寫。也不要使用漢語拼音和小眾的英文縮寫。可以使用常見的其意義被大眾熟知的英文縮寫或英文字典中定義的縮寫。
字段命名使用完整名稱,禁止縮寫
反例:uid、pid。 //說明:使用完整名稱,提高可讀性,修改為“user_id”、“person_id”。(7)禁止在命名字段時,重復表的名稱
例如,在名employe的表中禁止使用名為employee_lastname的字段。
(8)禁止在命名字段時,包含數據類型。
(9)表達是與否概念的字段,必須使用is_xxx的方式命名,數據類型是unsigned tinyint(1表示是,0表示否)。
說明:任何字段如果為非負數,則必須是unsigned。注意:POJO類中的任何布爾類型的變量,都不要加is前綴,需要在中設置從is_xxx到xxx的映射關系。數據庫表示是與否的值,使用tinyint類型,堅持is_xxx的命名方式是為了明確其取值含義與取值范圍。
正例:表達邏輯刪除的字段名is_deleted,1表示刪除,0表示未刪除。2.3數據庫字段類型規范
(1)如果存儲的字符串長度幾乎相等,則使用char定長字符串類型。
例如,11位手機號,郵編(postcode)。
這種固定長度的純數字,也不要用int類型或long類型,因為只有數字參與了運算,才用數值型。
(2)小數類型為decimal,禁止使用float和double類型。
在存儲時,float和double類型存在精度損失的問題,很可能在比較值的時候,得到不正確的結果。如果存儲的數據范圍超過decimal的范圍,那么建議將數據拆成整數和小數并分開存儲。
(3)整型int定義中不添加長度
比如使用INT,而不是INT(4)。
(4)varchar是可變長字符串,不預先分配存儲空間
禁止使用varchar類型作為主鍵。
長度不要超過5000個字符,如果存儲長度大于此值,則應定義字段類型為text,獨立出來一張表,用主鍵來對應,避免影響其他字段的索引效率。
(5)禁止使用blob、text類型保留大文本、文件、圖片
建議使用其他方式存儲,MySQL只保存指針信息。
一列需要占很大空間的字段,一定要單獨拎出來,不要和常用信息放一張表。
舉個例子: 文章的信息和文章的內容,這一定要分成兩個表。否則會給你的文章性能帶來極大的挑戰。因為很多情況下,查看文章列表,根本不需要查看到文章的內容。
(6)所有字段在設計時,必須有默認值
字符型的默認值為一個空字符值串‘’,數值型的默認值為數值0,邏輯型的默認值為數值0。
系統中所有邏輯型中數值0表示為“假”,數值1表示為“真”,datetime、smalldatetime類型的字段沒有默認值,必須為NULL。
除以下數據類型timestamp、image、datetime、smalldatetime、uniqueidentifier、binary、sql_variant、varbinary外
(7)IP地址使用unsigned int類型。
這樣比較節約存儲空間
select INET_ATON('192.0.0.0') select INET_NTOA(3221225472)(8)避免使用NULL字段
NULL字段很難查詢優化、NULL字段的索引需要額外空間、NULL字段的復合索引無效
(9)多表中的相同列,必須保證列定義一致。
(10)不建議使用ENUM類型,使用TINYINT來代替。
1)、假如一個設計不合理的ENUM字段,給程序員帶來的就完全是夢魘了,比如一個enum字段的范圍是(‘0’,‘1’,‘2’,‘3’,‘4’,‘5’),而enum的枚舉值對應的索引是從1開始的,因此,insert into table (enum)values(1),插入的并不是1,而是0
(2)、另外假如你在設計好enum的枚舉字段范圍并使用了一段時間后,再到字段范圍中加一個枚舉值,并且不是加在最后,那么也就相當于把原來的范圍都改變了索引值,也就是當你在查詢的時候直接查詢值(并加上單引號),將不會使用enum自身隱藏的索引值來獲取結果了
(3)、如果是純數值型,還是建議采用tinyint字段吧,畢竟它也只占一個字節,即使出現贓數據,也可以被接受,不象enum,如果純數字型范圍,更改了索引,你就不知道你查詢的值是否正確了
(4)、如果字段是字符串,并且長度固定,可以嘗試用char,如果是數值型,還是用tinyint吧,比較安全穩定,而且即使遷移,也不會出現太多問題
總結
以上是生活随笔為你收集整理的数据库表设计(一):字段设计规范和命名规范的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ie以及ie内核浏览器连不上网,其他浏览
- 下一篇: linux cmake编译源码,linu