MySQL 數據庫設計經驗總結

背景

此文僅在數據庫設計層面進行探討,數據庫的運維與底層調優不在討論範圍以內。html

更豐富的知識能夠在 MySQL 官網文檔 查閱。前端

學習官方文檔也是一種好的習慣,能更系統更全面的掌握某一領域的知識,具體知識點也能夠經過搜索引擎快速獲取,可是很難讓你深刻到細節或者上升到宏觀層面。mysql

基礎知識

存儲引擎

  • 一般來講,咱們作業務開發,指定存儲引擎爲 InnoDB 便可。

字符集

  • 一般來講,只要指定爲 utf8 便可。git

  • 若是業務中須要使用 emoji 表情,那麼就必需要設置爲 utf8mb4sql

MySQL 能夠在 server 級、database 級、table 級、column 級進行字符集的設置。數據庫

數據庫設計

總則

  • 命名以「_」分割
數據庫層面仍是推薦使用「_」做爲分割,這裏多說幾點:
一、約定俗成。長久以來不只 MySQL ,其餘數據庫也推薦使用「_」,這是一種 SQL 規範。
二、JSON 返回的數據通常也會將駝峯轉化爲「_」來分割。
三、JAVA POJO 對象仍是使用駝峯命名,如今的 JSON 轉換工具, ORM 工具能夠很便捷的指定參數來設置駝峯或者下劃線的偏好。

若是僅是使用 Mybatis ,爲了減小配置,也能夠考慮使用駝峯命名數據庫字段,或者使用 Mybatis 的 mapUnderscoreToCamelCase 的參數來解決。
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true" />
    </settings>
</configuration>
注意:resultType="hashMap" 的時候,不會生效,必定要有對應的實體。
Spring Boot 中指定 mybatis.configuration.mapUnderscoreToCamelCase=true
  • 綜合考慮應用場景,合理分庫分表
  • 合理冗餘字段,合理參考範式,以空間換時間
  • 儘可能保證數據庫單表操做,減小關聯查詢
  • 合理使用索引
  • 合理設計全部字段及表關聯
  • 儘可能避免在數據庫層面實現邏輯

儘可能避免使用觸發器,視圖,儲存過程,將業務邏輯與統計邏輯分離。不要在業務庫中大量統計計算。避免使用各類數據庫函數。mybatis

庫設計

  • 不容許物理刪除,須要邏輯刪除的使用 is_deleted 字段。除非是一些可有可無的關聯關係變動,能夠物理刪除再插入,而後經過操做日誌進行追蹤。
  • 日誌表、關聯關係表等固定數據表,須要包含 create_by, create_at 三個字段,業務表必須帶 create_by,create_at,update_by,update_at 四個字段。若是常常查詢,須要展現建立者修改者名稱,能夠增長 create_name 和 update_name 字段來進行冗餘,且應該使用真實姓名,name 僅作展現用,id 字段便於數據統計。
  • 流水錶是不可變動表,不須要帶 is_deleted,create_by 等字段。
  • 業務表狀態簡單的只要使用 status 字段便可,若是狀態複雜且要對不一樣狀態分組,能夠考慮使用 status_group 之類的額外字段來進行簡化。

表設計

  • 不建議以 「t_」 開頭

通常來講以「t_」開頭是爲了表示這是一張表,區別於視圖,觸發器,存儲過程等。而如今互聯網架構通常不建議使用視圖,觸發器,存儲過程等。並且不少企業只有一個庫,全是 t_ 開頭的數十上百張表,根本不知道怎麼快速檢索。架構

  • 直接使用業務對象爲表名 order,也不建議使用複數形式

若是已經按照功能模塊作了數據庫的拆分,能夠不要使用任何前綴,直接使用表名,如 order 。若是還在使用一個庫放全部的表的話,那就最好已模塊名開頭,比較客服系統的工單表,能夠命名爲 cs_job 。oracle

注意:不要與數據庫關鍵字衝突運維

  • 關係表以 「_rel」 結尾( rel 這個結尾不必定很合適,有更好的能夠推薦)
  • 日誌表以 「_log」 結尾
  • 表名要簡約(這一點可能也挺難,儘可能避免拼音做爲表名,英文能夠適當採起縮寫,好比 rel-關聯關係 或者 corp-公司,可是也要避免濫用縮寫,或者本身創造縮寫 )

字段設計

  • 每張表都應該有獨立的 id 字段,不論是自增字段仍是本身制定的 id(uuid 及其餘類型的惟一主鍵均可以,如某寶的訂單號和支付 ID )

擴展知識點:第二範式 聚簇索引 非聚簇索引

  • 儘可能保證全部字段非空
更新時間,更新者ID,更新者姓名等字段能夠根據本身喜愛設置初始值或者爲空
支付時間,退款時間,發貨時間,收貨時間等業務上後續發生的行爲能夠爲空
其餘字段一概不爲空,更好的數據庫約束,減小理解不一致和性能損耗。

B.4.4.3 Problems with NULL Values

22.2.7 How MySQL Partitioning Handles NULL

  • 注意整型的長度修飾並不表明字段存儲值的範圍,只是展現長度。

這一點不少開發人員都沒有注意過。咱們仍是看一下官網的描述。11.1.1 Numeric Type Overview int(11) 中的 11 只是展現位數,並不影響實際存儲的值,配合 ZEROFILL ,改變的只是查詢的值,好比數據庫字段定義爲 INT(4),值爲 1,啓用了 ZEROFILL, SELECT 的結果展現爲 0001。

INT[(M)] [UNSIGNED] [ZEROFILL]

A normal-size integer. The signed range is -2147483648 to 2147483647. The unsigned range is 0 to 4294967295.

M indicates the maximum display width for integer types. The maximum display width is 255. Display width is unrelated to the range of values a type can contain, as described in Section 11.2, 「Numeric Types」. For floating-point and fixed-point types, M is the total number of digits that can be stored.

MySQL supports the SQL standard integer types INTEGER (or INT) and SMALLINT. As an extension to the standard, MySQL also supports the integer types TINYINT, MEDIUMINT, and BIGINT.

若是要考慮數據遷移的話,儘可能使用 INT 或者 SMALLINT。
  • 整型合理使用UNSIGNED

整型的UNSIGNED很魔性,須要結合實際場景使用。ZEROFILL 默認使用 UNSIGNED。UNSIGNED 修飾有兩大做用:一是保證列爲非負數,二是能夠擴大使用範圍,我的推薦使用 UNSIGNED。

  • 確保每列的原子性,每一個字段的含義應該惟一(第一範式)

不能用一個字段來表示兩種邏輯含義,還有就是字段要存儲直接的字面量,不要存儲須要計算的值,好比使用類 Linux 文件系統權限的模式來處理狀態

  • 表中不能存儲文件,只能存放 url

若是使用了分佈式文件儲存系統,或者用了第三方的文件存儲服務。能夠不用存儲域名前綴,應用層實現拼接或者前端處理。

  • 儘可能避免使用 text 或 blog 字段

確實須要存儲的能夠考慮拆表,將基本字段與擴展大字段分開。甚至能夠考慮採用 MongoDB 之類的數據庫才存儲大量的文本表。

索引設計

  • 儘可能使用單列索引,避免使用聯合索引,不要建 3 列以上的聯合索引。
  • 單表的索引數量不要過多,控制在6個之內,索引的創建和更新也須要時間,能夠關注因此佔用的存儲空間,多列索引還要注意保持順序才能生效,多列索引也要考慮每一個字段的檢索效率,效率高的字段在前。
索引失效的幾種狀況:
一、字段值的區分度過小,好比性別的 0,1
二、like 使用了前模糊匹配 like '%asdf'
三、使用了函數 date(birthday) 或者進行了計算 a + 50
四、違反左匹配原則 如聯合索引 a, b 實際查詢使用順序爲 b, a
五、索引列中含有 NULL
相關文章
相關標籤/搜索