-
名稱
- 建表的時候,給表,字段和索引起個好名字
- 見名知意:好的名字能夠降低溝通和維護的成本
- 名字不宜過長,盡量控制在30個字符以內
- 大小寫
- 名字盡量都用小寫字母,因為從視覺上,小寫字母更容易讓人讀懂
- 全部大寫,看起來不太直觀,一部分大寫一部分小寫更不可以
- 分隔符
- 單詞之間沒有分隔,或者單詞間用駝峰標識,或者單詞間用空格分隔,或者單詞間用@分隔,都不建議
- 建議在單詞之間使用下橫線_分隔
- 表名
- 對于表名,在言簡意賅,見名知意的基礎上,建議帶上業務前綴
- 如果是訂單相關的業務表,可以在表名前面加個前綴:order_,比如order_pay
- 這樣做的好處是為了方便歸類,把相同業務的表,可以非常快速的聚集在一起
- 如果哪天有非訂單的業務,比如:金融業務,也需要建一個名字叫做pay的表,可以取名:finance_pay,就能非常輕松的區分,這樣就不會出現同名表的情況
- 字段名稱
- 比如有些表用flag表示狀態,而有些表使用status表示狀態,可以統一一下,使用status表示狀態
- 如果一個表使用了另一個表的主鍵,可以在另一張表的名后面,加_id,例如:product_spu_id
- 創建時間,可以統一為:create_time,修改時間統一為:update_time
- 刪除狀態固定位:delete_status
- 還有很多公共字段,在不同表之間,可以使用全局統一的命名規則,定義成相同的名稱,以便大家好理解
- 索引名
- 普通索引和聯合索引,其實是一類,在建立該類索引時,可以加ix_前綴,比如:ix_product_status
- 唯一索引,可以加ux_前綴,比如:ux_product_code
- 建表的時候,給表,字段和索引起個好名字
-
字段類型
- 時間格式的數據有:date,datetime,timestamp等可以選擇
- 字符類型的數據有:varchar,char,text等可以選擇
- 數字類型數據有:int,bigint,smallint,tinyint等可以選擇
- 如果字段類型選大了,比如原本只有1-10之間的10個數字,結果選了bigint,他占了8個字節,其實1-10之間的10個數字,每個數字1個字節就能保存,選擇tinyint更為合適,這樣會白白浪費7個字節的空間
- 如果字段類型選小了,比如:一個18位的id字段,選擇了int類型,最終數據會保存失敗
- 所以選擇一個合適的字段類型,是很重要的
- 參考原則:
- 盡可能選擇占用存儲空間小的字段類型,在滿足正常業務需求的情況下,從小到大,往上選
- 如果字符串長度固定,或者差別不大,可以選擇char類型,如果字符串長度差別較大,可以選擇varchar類型
- 是否字段,可以選擇bit類型
- 枚舉字段:可以選擇tinyint字段
- 主鍵字段:可以選擇bigint類型
- 金額字段:可以選擇decimal類型
- 時間字段:可以選擇timestamp或datetime類型
-
字段長度
- 在mysql中除了varchar和char是代表字符長度外,其余類型都是代表字節長度
- bigint(4),bigint實際長度為8個字節,現在有一個數據a=1.a顯示4個字節,所以在不滿足4個字節時前面填充0(前提是該字段設置了zerofill屬性),比如:0001,當滿了4個字節時,比如現在數據是a=123456,他會按照實際的長度顯示,比如123456,但需要注意的是,有些mysql客戶端即使滿了4個字節,也只能顯示4個字節的內容,比如會顯示成:1234,所以bigint(4),這里的4表示顯示的長度為4個字節,實際長度還是占8個字節
-
字段個數
- 建表時需要對字段的個數做一定的限制
- 如果表的字段個數非常多,可以將一張大表拆分成多張小表,這幾張表的主鍵相同
- 建議每表的字段個數,不超過20個
-
主鍵
- 在創建表時,一定要創建主鍵,因為主鍵自帶了主鍵索引,相比于其他索引,主鍵索引的查詢效率更高,因為他不需要回表
- 主鍵還是天然的唯一索引,可以根據他來判重
- 在單個數據庫中,主鍵可以通過auto_increment,設置為自動增長的
- 但在分布式數據庫中,特別是做了分庫分表的業務庫中,主鍵最好由外部算法(比如:雪花算法)生成,他能夠保證生成的id是全局唯一的
- 主鍵建議保存跟業務無關的值,減少業務耦合性,方便今后的擴展
- 不過也有一些一對一的表關系,比如:用戶表和用戶擴展表,在保存數據時是一對一的關系,這樣用戶擴展表的主鍵,可以直接保存用戶表的主鍵
-
存儲引擎
- 在mysql8之前的版本,默認的存儲引擎是myisam,而mysql8以后的版本,默認的存儲引擎是innodb
- myisam的索引和數據分開存儲,有利用查詢,但他不支持事務和外鍵等功能
- innodb雖然查詢性能稍微弱一點,但他支持事務和外鍵等,功能更強大一些
- 以前的建議是:讀多寫少的表,用myisam存儲引擎,而寫多讀多的表,用innodb
- 但隨著mysql對innodb存儲引擎性能的不斷優化,現在myisam和innodb查詢性能相差已經越來越小
- 所以在使用mysql8之后的版本時,直接使用默認的innodb存儲引擎即可,無需額外修改存儲引擎
-
not null
- 定義字段時,應該盡可能明確字段為NOT NULL
- 在innodb中,需要額外的空間存儲null值,需要占用更多的空間
- null值可能會導致索引失效
- null值只能用is null或者is not null判斷,用=號判斷永遠返回false
- 因此,建議定義字段時,能定義為not null,就定義為not null
- 如果某個字段直接定義成not null,萬一有些地方忘了給該字段寫值,就會insert不了數據
- alter table product_sku add column brand_id int(10) not null default 0;
- 定義字段時,應該盡可能明確字段為NOT NULL
-
外鍵
- 在mysql中,是存在外鍵的
- 外鍵存在的主要作用是:保證數據的一致性和完整性
- foreign key(cid) references class(id),student表的cid字段,保存的class表的id,這時通過foreign key增加了一個外鍵
- 如果直接通過student表的id刪除數據,會報異常:a foreign key constraint fails
- 必須先刪除class表對應的cid那條數據,再刪除student表的數據才行,這樣能夠保證數據的一致性和完整性
- 只有存儲引擎是innodb時,才能使用外鍵
- 一般不建議使用外鍵,因為這類系統更多的是為了性能考慮,寧可犧牲一點數據一致性和完整性
- 除了外鍵之外,存儲過程和觸發器也不建議使用,會影響性能
-
索引
- 在建表時,除了指定主鍵索引外,還需要創建一些普通索引
- id int(10) primary key auto_increment
- 普通索引:key ‘ix_spu_id’ (‘spu_id’) using btree
- 后面查詢表的時候,效率更高
- 但索引字段也不能建的太多,可能會影響保存數據的效率,因為索引需要額外的存儲空間
- 建議單表的索引個數不要超過5個
- 如果在建表時,發現索引個數超過5個了,可以刪除部分普通索引,改成聯合索引
- 在創建聯合索引時,需要注意最左匹配原則,不然,建的聯合索引效率可能不高
- 對于數據重復率非常高的字段,比如:狀態,不建議單獨創建普通索引,因為即使加了索引,如果mysql發現全表掃描效率更高,可能會導致索引失效
-
時間字段
- 時間字段的類型,目前mysql支持:date,datetime,timestamp,varchar等
- varchar類型可能是為了跟接口保持一致,接口中的時間類型為String
- 但是如果需要通過時間范圍查詢數據,效率會非常低,因為這種情況沒法走索引
- date類型主要為了保存日期,比如:2024-07-02,不適合保存日期和時間,比如:2024-07-02 21:05:30
- 而datetime和timestamp類型更適合保存日期和時間
- timestamp:用4個字節來保存數據,他的取值范圍為1970-01-01 00:00:00UTC - 2038-01-19 03:14:07,此外,還跟時區有關
- datetime:用8個字節保存數據,他的取值范圍為:1000-01-01 00:00:00 - 9999-12-31 23:59:59,他和時區無關
- 優先推薦使用datetime類型保存時間和日期,可以保存的時間范圍更大
- 在給時間字段設置默認值時,建議不要設置成:0000-00-00 00:00:00 不然查詢表時可能會轉換不了直接報錯
-
金額字段
- mysql中有多個字段可以表示浮點數:float,double,decimal等
- float和double可能會丟失精度,因此推薦使用decimal類型保存金額
- 一般這樣定義浮點數:decimal(m,n)
- 其中的n是指小數的長度,而m是指整數加小數的總長度
- 比如:decimal(10,2),則表示整數長度為8,并且保留2位小數
-
JSON字段
- 某個字段保存的數據值不固定
- mysql支持按字段,查詢json中的數據
-
唯一索引
- 可以給單個字段,加唯一索引
- 也可以給多個字段,加一個聯合的唯一索引,聯合的唯一索引,字段值出現null時,則唯一性約束可能會失效
- 創建唯一索引時,相關字段一定不能包含null值,否則唯一性會失效
-
字符集
- mysql支持的字符集有很多:latin1,utf-8,utf8mb4,GBK
- GBK:長度2,支持中文,但是不是國際通用的字符集
- UTF-8:長度3位,支持中英文混合場景,是國際通用字符集
- latin1:長度1位,mysql默認的字符集
- utf8mb4:長度4位,完全兼容UTF-8,用四個字節存儲更多的字符
- latin1容易出現亂碼問題,子啊實際項目中使用比較少
- 而GBK支持中文,但不支持國際通用字符,在實際項目中使用也不多
- 目前,mysql的字符集使用最多的還是utf-8和utf8mb4
- 其中utf-8占用3個字節,比utf8mb4的4個字節,占用更小的存儲空間
- 但UTF-8有個問題:無法存儲emoji表情,因為emoji表情需要4個字節,保存時會直接報錯
- 建議在建表時字符集設置成:utf8mb4,會省去很多不必要的麻煩
-
排序規則
- 在mysql中創建表時,有個collate參數可以設置排序規則
- collate=utf8mb4_bin
- 字符排序規則跟字符集有關,比如字符集如果是utf8mb4,則字符排序規則也是以utf8mb4_開頭的,常用的有:utf8mb4_general_ci,utf8mb4_bin等
- 其中utf8mb4_general_ci排序規則,對字母的大小寫不敏感,不區分大小寫
- 而utf8mb4_bin排序規則,對字符大小寫敏感,區分大小寫
- 比如:order表中有一條記錄,name的值是大寫的YOYO,但我們用小寫的yoyo去查,select * from order where name = ‘yoyo’;
- 如果字符排序規則是utf8mb4_general_ci,則可以查出大寫的YOYO的數據
- 如果字符排序規則是utf8mb4_bin,則查不出來
- 因此,字符排序規則,要根據實際的業務場景選擇,否則容易出現問題
-
大字段
- 大字段,即占用較多存儲空間的字段,比如用戶評論
- 如果直接定義為text類型,可能會浪費存儲空間,所以建議講這類字段定義為varchar類型的存儲效率更高
- 如果是合同數據,一個合同可能會占幾MB,可以保存到mongodb中,然后在mysql的業務表中,保存mongodb表的id
-
冗余字段
- 在設計表的時候,為了性能考慮,提升查詢速度,有時可以冗余一些字段
- 對查詢性能有利,但需要額外的存儲空間,還可能會有數據不一致的情況,比如用戶名稱修改了
- 我們在實際業務場景中,需要總和評估,冗余字段方案不適用于所有的業務場景
-
注釋
-
在做表的設計時,一定要把表和相關字段的注釋加好,并且經常需要更新這些注釋
-
‘valid_status’ tinyint(1) not null default 1 comment ‘有效狀態 1:有效 0 :無效’
-
特別是有些狀態類型的字段,比如valid_status字段,該字段表示有效狀態,1:有效,0:無效,
-
讓人可以一目了然,表和字段是干什么用的,字段的值可能有哪些
-