SQL Server 數據庫表設計的18條軍規
當前位置:點晴教程→知識管理交流
→『 技術文檔交流 』
前言對于后端開發同學來說,訪問數據庫,是代碼中必不可少的一個環節。 系統中收集到用戶的核心數據,為了安全性,我們一般會存儲到數據庫,比如:mysql,oracle等。 后端開發的日常工作,需要不斷的建庫和建表,來滿足業務需求。 通常情況下,建庫的頻率比建表要低很多,所以,我們這篇文章主要討論建表相關的內容。 如果我們在建表的時候不注意細節,等后面系統上線之后,表的維護成本變得非常高,而且很容易踩坑。 今天就跟大家一起聊聊,數據庫建表的18個小技巧。 文章中介紹的很多細節,我在工作中踩過坑,并且實踐過的,非常有借鑒意義,希望對你會有所幫助。 1.名字建表的時候,給 1.1 見名知意名字就像 好的名字,言簡意賅,見名知意,讓人心情愉悅,能夠提高溝通和維護成本。 壞的名字,模擬兩可,不知所云。而且顯得雜亂無章,看得讓人抓狂。 反例:
你看了可能會一臉懵逼,這是什么騷操作? 正例:
1.2 大小寫名字盡量都用 反例:
全部大寫,看起來有點不太直觀。而一部分大寫,一部分小寫,讓人看著更不爽。 正例:
名字還是使用全小寫字母,看著更舒服。 1.3 分隔符很多時候,名字為了讓人好理解,有可能會包含多個單詞。 那么,多個單詞間的 反例:
單詞間沒有分隔,或者單詞間用駝峰標識,或者單詞間用空格分隔,或者單詞間用@分隔,這幾種方式都不太建議。 正例:
強烈建議大家在單詞間用 1.4 表名對于表名,在言簡意賅,見名知意的基礎之上,建議帶上 如果是訂單相關的業務表,可以在表名前面加個前綴: 例如:order_pay、order_pay_detail等。 如果是商品相關的業務表,可以在表名前面加個前綴: 例如:product_spu,product_sku等。 這樣做的好處是為了方便歸類,把相同業務的表,可以非常快速的聚集到一起。 另外,還有有個好處是,如果哪天有非訂單的業務,比如:金融業務,也需要建一個名字叫做pay的表,可以取名:finance_pay,就能非常輕松的區分。 這樣就不會出現 1.5 字段名稱
比如有些表,使用flag表示狀態,另外的表用status表示狀態。 可以統一一下,使用status表示狀態。 如果一個表使用了另一個表的主鍵,可以在另一張表的名后面,加 在product_sku表中有個字段,是product_spu表的主鍵,這時候可以取名:product_spu_id或product_spu_sys_no。 還有創建時間,可以統一成:create_time,修改時間統一成:update_time。 刪除狀態固定為:delete_status。 其實還有很多公共字段,在不同的表之間,可以使用全局統一的命名規則,定義成相同的名稱,以便于大家好理解。 1.6 索引名在數據庫中,索引有很多種,包括:主鍵、普通索引、唯一索引、聯合索引等。 每張表的主鍵只有一個,一般使用: 普通索引和聯合索引,其實是一類。在建立該類索引時,可以加 唯一索引,可以加 2.字段類型在設計表時,我們在選擇 時間格式的數據有:date、datetime和timestamp等等可以選擇。 字符類型的數據有:varchar、char、text等可以選擇。 數字類型的數據有:int、bigint、smallint、tinyint等可以選擇。 說實話,選擇很多,有時候是一件好事,也可能是一件壞事。 如何選擇一個 如果字段類型選大了,比如:原本只有1-10之間的10個數字,結果選了 其實,1-10之間的10個數字,每個數字 這樣會白白浪費7個字節的空間。 如果字段類型擇小了,比如:一個18位的id字段,選擇了 所以選擇一個合適的字段類型,還是非常重要的一件事情。 以下原則可以參考一下:
3.字段長度前面我們已經定義好了 比如:varchar(20),biginit(20)等。 那么問題來了, 答:在mysql中除了 biginit(n) 這個 假如我們定義的字段類型和長度是:bigint(4),bigint實際長度是 現在有個數據a=1,a顯示4個字節,所以在不滿4個字節時前面填充0(前提是該字段設置了zerofill屬性),比如:0001。 當滿了4個字節時,比如現在數據是a=123456,它會按照實際的長度顯示,比如:123456。 但需要注意的是,有些mysql客戶端即使滿了4個字節,也可能只顯示4個字節的內容,比如會顯示成:1234。 所以bigint(4),這里的4表示顯示的長度為4個字節,實際長度還是占8個字節。 4.字段個數我們在建表的時候,一定要對 我之前見過有人創建的表,有幾十個,甚至上百個字段,表中保存的數據非常大,查詢效率很低。 如果真有這種情況,可以將一張 建議每表的字段個數,不要超過 5. 主鍵在創建表時,一定要創建 因為主鍵自帶了主鍵索引,相比于其他索引,主鍵索引的查詢效率最高,因為它不需要回表。 此外,主鍵還是天然的 在 但在 除此之外,主鍵建議保存跟業務無關的值,減少業務耦合性,方便今后的擴展。 不過我也見過,有些一對一的表關系,比如:用戶表和用戶擴展表,在保存數據時是一對一的關系。 這樣,用戶擴展表的主鍵,可以直接保存用戶表的主鍵。 6.存儲引擎在 之前我們還在創建表時,還一直糾結要選哪種存儲引擎?
而 以前的建議是:讀多寫少的表,用myisam存儲引擎。而寫多讀多的表,用innodb。 但雖說mysql對innodb存儲引擎性能的不斷優化,現在myisam和innodb查詢性能相差已經越來越小。 所以,建議我們在使用 7. NOT NULL在創建字段時,需要選擇該字段是否允許為 我們在定義字段時,應該盡可能明確該字段 為什么呢? 我們主要以innodb存儲引擎為例,myisam存儲引擎沒啥好說的。 主要有以下原因:
因此,建議我們在定義字段時,能定義成NOT NULL,就定義成NOT NULL。 但如果某個字段直接定義成NOT NULL,萬一有些地方忘了給該字段寫值,就會 這也算合理的情況。 但有一種情況是,系統有新功能上線,新增了字段。上線時一般會先執行sql腳本,再部署代碼。 由于老代碼中,不會給新字段賦值,則insert數據時,也會報錯。 由此,非常有必要給NOT NULL的字段設置默認值,特別是后面新增的字段。 例如:
8.外鍵在mysql中,是存在 外鍵存在的主要作用是:保證數據的 例如:
有個班級表class。 然后有個student表:
其中student表中的cid字段,保存的class表的id,這時通過 這時,如果你直接通過student表的id刪除數據,會報異常:
必須要先刪除class表對于的cid那條數據,再刪除student表的數據才行,這樣能夠保證數據的一致性和完整性。
如果只有兩張表的關聯還好,但如果有十幾張表都建了外鍵關聯,每刪除一次主表,都需要同步刪除十幾張子表,很顯然性能會非常差。 因此,互聯網系統中,一般建議不使用外鍵。因為這類系統更多的是為了性能考慮,寧可犧牲一點數據一致性和完整性。 除了 9. 索引在建表時,除了指定 例如:
在創建商品表時,使用spu_id(商品組表)和brand_id(品牌表)的id。 像這類保存其他表id的情況,可以增加普通索引:
后面查表的時候,效率更高。 但索引字段也不能建的太多,可能會影響保存數據的效率,因為索引需要額外的存儲空間。 建議單表的索引個數不要超過: 如果在建表時,發現索引個數超過5個了,可以刪除部分 順便說一句:在創建聯合索引的時候,需要使用注意 對于數據重復率非常高的字段,比如:狀態,不建議單獨創建普通索引。因為即使加了索引,如果mysql發現 如果你對索引失效問題比較感興趣,可以看看我的另一篇文章《聊聊索引失效的10種場景,太坑了》,里面有非常詳細的介紹。 10.時間字段
但如果哪天我們要通過時間范圍查詢數據,效率會非常低,因為這種情況沒法走索引。
而 但它們有略微區別。
優先推薦使用
11.金額字段mysql中有多個字段可以表示浮點數:float、double、decimal等。 而 一般我們是這樣定義浮點數的:decimal(m,n)。 其中 假如我們定義的金額類型是這樣的:decimal(10,2),則表示整數長度是8位,并且保留2位小數。 12. json字段我們在設計表結構時,經常會遇到某個字段保存的數據值不固定的需求。 舉個例子,比如:做異步excel導出功能時,需要在異步任務表中加一個字段,保存用戶通過前端頁面選擇的查詢條件,每個用戶的查詢條件可能都不一樣。 這種業務場景,使用傳統的數據庫字段,不太好實現。 這時候就可以使用MySQL的json字段類型了,可以保存json格式的結構化數據。 保存和查詢數據都是非常方便的。 MySQL還支持按字段名稱或者字段值,查詢json中的數據。 13.唯一索引
你可以給單個字段,加唯一索引,比如:組織機構code。 也可以給多個字段,加一個聯合的唯一索引,比如:分類編號、單位、規格等。 單個的唯一索引還好,但如果是聯合的唯一索引,字段值出現null時,則唯一性約束可能會失效。 關于唯一索引失效的問題,感興趣的小伙伴可以看看我的另一篇文章《明明加了唯一索引,為什么還是產生重復數據?》。
14.字符集mysql中支持的 這4種字符集情況如下:
而 從目前來看,mysql的字符集使用最多的還是: 其中 但utf-8有個問題:即無法存儲emoji表情,因為emoji表情一般需要4個字節。 由此,使用utf-8字符集,保存emoji表情時,數據庫會直接報錯。 所以,建議在建表時字符集設置成: 15. 排序規則不知道,你關注過沒,在mysql中創建表時,有個 例如:
它是用來設置 字符排序規則跟字符集有關,比如:字符集如果是 其中utf8mb4_general_ci排序規則,對字母的大小寫不敏感。說得更直白一點,就是不區分大小寫。 而utf8mb4_bin排序規則,對字符大小寫敏感,也就是區分大小寫。 說實話,這一點還是非常重要的。 假如order表中現在有一條記錄,name的值是大寫的YOYO,但我們用小寫的yoyo去查,例如:
如果字符排序規則是utf8mb4_general_ci,則可以查出大寫的YOYO的那條數據。 如果字符排序規則是utf8mb4_bin,則查不出來。 由此,字符排序規則一定要根據實際的業務場景選擇,否則容易出現問題。 16.大字段我們在創建表時,對一些特殊字段,要額外關注,比如: 比如:用戶的評論,這就屬于一個大字段,但這個字段可長可短。 但一般會對評論的總長度做限制,比如:最多允許輸入500個字符。 如果直接定義成 當然,我還見過更大的字段,即該字段直接保存合同數據。 一個合同可能會占 在mysql中保存這種數據,從系統設計的角度來說,本身就不太合理。 像合同這種非常大的數據,可以保存到 17.冗余字段我們在設計表的時候,為了性能考慮,提升查詢速度,有時可以冗余一些字段。 舉個例子,比如:訂單表中一般會有userId字段,用來記錄用戶的唯一標識。 但很多訂單的查詢頁面,或者訂單的明細頁面,除了需要顯示訂單信息之外,還需要顯示用戶ID和用戶名稱。 如果訂單表和用戶表的數據量不多,我們可以直接用userId,將這兩張表join起來,查詢出用戶名稱。 但如果訂單表和用戶表的數據量都非常多,這樣join是比較消耗查詢性能的。 這時候我們可以通過冗余字段的方案,來解決性能問題。 我們可以在訂單表中,可以再加一個userName字段,在系統創建訂單時,將userId和userName同時寫值。 當然訂單表中歷史數據的userName是空的,可以刷一下歷史數據。 這樣調整之后,后面只需要查詢訂單表,即可查詢出我們所需要的數據。 不過冗余字段的方案,有利也有弊。 對查詢性能有利。 但需要額外的存儲空間,還可能會有數據不一致的情況,比如用戶名稱修改了。 我們在實際業務場景中,需要綜合評估,冗余字段方案不適用于所有業務場景。 18.注釋我們在做表設計的時候,一定要把表和相關字段的注釋加好。 例如下面這樣的:
表和字段的注釋,都列舉的非常詳細。 特別是有些狀態類型的字段,比如:valid_status字段,該字段表示有效狀態, 1:有效 0:無效。 讓人可以一目了然,表和字段是干什么用的,字段的值可能有哪些。 最怕的情況是,你在表中創建了很多status字段,每個字段都有1、2、3、4、5、6、7、8、9等多個值。 沒有寫什么注釋。 誰都不知道1代表什么含義,2代表什么含義,3代表什么含義。 可能剛開始你還記得。 但系統上線使用一年半載之后,可能連你自己也忘記了這些status字段,每個值的具體含義了,埋下了一個巨坑。 由此,我們在做表設計時,一定要寫好相關的注釋,并且經常需要更新這些注釋。 該文章在 2024/4/9 23:51:22 編輯過 |
關鍵字查詢
相關文章
正在查詢... |