1. 程式人生 > >MySQL學習筆記_資料庫設計規範

MySQL學習筆記_資料庫設計規範

資料庫設計的規範:

一.資料庫命名規範
二.資料庫基本設計規範
三.資料庫索引設計規範
四.資料庫欄位設計規範
五.資料庫SQl開發規範
六.資料庫操作行為規範


一.資料庫命名規範

1.所有的資料庫名稱和表名稱必須使用小寫字母並使用下劃線分割
  這是因為MySQL資料檔案就是Linux下的一個問題,Linux是大小寫敏感的,所以MySQL資料庫和表的名稱也是大小寫敏感的:
  Dbname和dbName代表兩個不同的資料庫
  Table和table代表兩個不同的表
  為了不引起奇異,規定資料庫名稱和表名稱必須使用小寫字母+下劃線的方式

2.所有的資料庫名稱禁止使用MySQL保留關鍵字
  select id.username,from,age from tb_user;

  上面的SQL語句有兩個from,第一個是欄位,第二個是SQL關鍵字,MySQL在執行查詢時,並不能區分是關鍵字還是資料欄位,那麼需要:
  select id.username,`from`,age from tb_user;
  需要在from資料欄位加反向引號,為了避免出現奇異,禁止資料欄位使用SQL關鍵字。

  MySQL關鍵字查詢:
  http://dev.mysql.com/doc/refman/5.7/en/keywords.html

3.資料庫名稱命名要見名識意,不要超過32字元

4.臨時庫表的字首必須以tmp開頭,並以日期為字尾
  備份庫表的字首必須以bak開頭,並以日期為字尾

5.所有儲存相同資料的列名和列型別必須一致

  e.g.我們在使用者資訊表和訂單表中都會儲存使用者ID,customer_id,那麼要求兩個表中使用者ID的名稱和型別必須一致。
  這樣的列一般作為關聯列使用,要是資料型別不一致,在進行聯合查詢的時候,MySQL需要先進行型別轉換,有可能導致索引失效,降低查詢效率。

二.資料庫基本設計規範
1.表引擎使用InnoDB
  在MySQL5.5以前Myisam是預設的儲存引擎,MySQL5.5以後InnoDB為預設的儲存引擎。
  InnoDB在MySQL5.6及以後進行了很好的優化,InnoDB是一種支援事務、行級鎖、有更好的恢復性,高併發下效能更好的儲存引擎。

2.資料庫和表的字符集統一使用UTF8編碼格式

  [說明]UTF8中一箇中文字元佔3個位元組,其他的字元佔一個位元組。

3.所有的表和欄位都需要添加註釋 comment

4.儘量控制單表資料量的大小,建議控制在500萬以內
  [說明]MySQL在32位作業系統下,單個表的大小是不能超過2G的;
  當資料庫資料過大的時候,可以考慮歷史資料歸檔,分庫分表的手段來控制資料量的大小。

5.儘量做到冷熱資料分離,減小表的寬度
  減小磁碟IO,保證熱資料的記憶體快取命中率;
  更有效的利用快取,避免過多的讀入無用的冷資料,避免使用select *
  把經常使用的資料放到一個表裡面。

6.禁止在表中建立預留欄位

7.禁止在資料庫中儲存圖片、檔案等二進位制的資料

8.禁止在生產環境做資料庫壓力測試

三.資料庫索引設計規範
(建立索引的目的,通過索引查詢資料,減少磁碟的隨機IO,提高查詢的效能)

1.限制每張表的索引個數,建議單張表的索引不超過5個
  索引並不是越多越好,索引可以提高查詢效率,同樣降低可以降低查詢效率,這是因為MySQL在進行查詢的時候,會根據現有的索引生產一個最有的查詢方案,索引過多導致生成查詢方案的時間變長,降低查詢的效率;
  索引可以提高查詢的效率,但降低了插入、修改資料的效率。

2. InnoDB表必須有一個主鍵
  InnoDB是一個索引組織表,即資料儲存的邏輯順序和索引順序是一致的。
  每個表可以有多個索引,但是每個表的儲存順序只有一種,當有多個索引的時候,InnoDB表會按照主鍵的順序來進行儲存,所以要求每個InnoDB在建立的時候,必須有一個主鍵,若果沒有主鍵,MySQL就會選擇第一個非空唯一索引作為儲存順序,如果沒有非空索引的話,MySQL就會自動生成一個6個位元組的主鍵,而自動生成的主鍵並不是效能最好的。
  【注意】
  (1)InnoDB的主鍵不能夠頻繁的變動,這是因為InnoDB是索引組織表,主鍵的變動會導致表中資料儲存的順序發生改變,影響表的效能。
  (2)主鍵不建議使用類似UUID,MD5,HASH,字串作,因為這些值一般無法保證資料的順序增長。
  以MD5值為列子,我們無法保證後面插入的資料的MD5主鍵值要比之前資料的MD5值要大,那麼儲存的時候所以會將其插入到比他大的索引後面,導致大量的資料需要向後移動,造成大量IO操作和佔用CPU資源的情況,建議使用MySQL的自增ID作為主鍵。
  (3)常見的索引建議
    SELECT,UPDATE,DELETE語句的WHERE從句中的列;
    包含ORDER BY,GROUP BY,DISTINCT中的欄位;
    多表JOIN的關聯列
  (4)對於頻繁的查詢優先考慮使用覆蓋索引;
    InnoDB中主鍵作為一級索引,當我們按照一個二級索引查詢資料的時候,InnoDB首先按照二級索引查詢到對應的子節點的位置,而二級索引的子節點中儲存的資料是該行主鍵的資訊,要得到真實的資料,還要通過主鍵進行二次查詢,而覆蓋索引中,二級索引的鍵值是可以獲得所有資料的,這樣避免了進行二次查詢。

 四.資料庫欄位設計規範
  1.優先選擇符合儲存需求的最小資料型別
    將字串轉化為數字型別進行儲存,e.g.將IP地址轉化為數字進行儲存,MySQL提供了兩個函式,在我們儲存的時候,呼叫INET_ATOM('255.255.255.255') = 429****95,將字串型別的IP地址轉換為數字型別,同樣在取資料的時候,使用INET_NTOA(429****95) = '255.255.255.255'函式,將數字型別的IP地址還原為字串

  2.對於非負資料採用無符號整型進行儲存
    無符號相對於有符號資料,可以多出一倍的儲存空間,e.g.
    SIGNED INT有符int型別的範圍在-2147483648到2147483647
    UNSIGNED INT無符int型別的儲存範圍在0-4294967295之間。

  3.MySQL中的VARCHAR(N)的N代表的是字元數,而不是位元組數,這和其他的一些資料庫中VARCHAR代表的儲存單位不太一樣,使用UTF8儲存漢字的時候,每個漢字佔3個位元組。

  4.避免使用TEXT、BLOB資料型別
    建議把BLOB和TEXT列單獨分離到擴充套件表中,TEXT和BLOB只能使用字首索引

  5.儘可能把所有的列定義為NOT NULL
    索引列為NULL時,需要額外佔用 索引空間儲存NULL狀態;
    進行列的比較和計算時,需要對NULL進行特殊處理,這樣有可能導致索引失效

  6.時間日期的儲存使用TIMESTAMP或DATETIME型別,不要使用字串儲存
    缺點:無法使用日期函式進行比較;用字串儲存日期佔用更多的空間,使用字串需要使用16位元組,要是使用DateType,那麼只需要8位元組;
    同樣的效果TIMESTAMP儲存只需要4個位元組,而DATETIME需要佔用8個位元組,但是TIMESTAMP只能儲存時間在1970-01-01 00:00:01到2038-01-19 03:14:07之間的時間,TIMESTAMP實質上是使用INT型別來儲存資料的,只是在顯示的時候,進行轉化。

  7.資料庫中儲存的浮點型別資料包括非精準浮點(float, double)和精準浮點資料型別(decimal)
    約定同財務相關的金額資料,一律使用decimal資料型別;
    decimal資料型別佔用的空間是由定義的寬度決定的,每4個位元組可以儲存9位數字,小數點單獨佔一個位元組;
    decimal資料型別可以用來儲存比bigint更大的整數資料,這比使用VARCHAR儲存資料更高效

五.資料庫SQL開發規範
  1.建議使用預編譯語句進行資料庫操作
    預編譯的SQL語句使用相同的查詢計劃,節省了MySQL生成查詢計劃的時間,而且可以防止SQL注入

  2.避免資料型別的隱式轉化
    當資料型別不一致的時候,MySQL會進行資料的隱式轉換,這會導致建立在列上的索引失效。

  3.充分使用表上已存在的索引
    (1)避免使用雙%進行查詢,e.g. LIKE '%123%' 或 LIKE '%123'都會導致列上的索引失效,但是使用 LIKE '123%' 的查詢方式是可以利用到索引的。
    (2)一個SQL只能利用複合索引中的一列進行範圍查詢
    如果A、B、C三列進行聯合查詢,A列進行範圍查詢,那麼B、C上的索引就不會再被用到了,此時我們應該將A列放在聯合索引的右側
    (3)使用left join和not exists來替換not in,後者有可能造成索引失效

   4.禁止使用Select * 進行查詢, 應該使用Select <欄位名> 進行查詢

   5.禁止使用不含欄位列名的Insert語句,不應該使用insert into t values(1, 2, 3)這樣的語句進行資料插入,而應該使用insert into t(a, b, c) values(1, 2, 3)這樣的語句進行插入操作,防止表結構變更造成插入錯誤。

   6.避免使用子查詢,儘量轉化為Join查詢方式
    子查詢無法使用索引;子查詢會產生臨時表表操作,而這些臨時表是沒有索引的,會消耗過多的CPU和IO資源。

   7.避免使用JOIN關聯過多的表
    每JOIN一個表就會佔用一部分記憶體,MySQL可以通過join_buffer_size設定這部分記憶體的大小;
    Join操作也會產生臨時表操作,影響查詢效率;
    MySQL最多允許關聯61個表,建議不要超過5個

   8.減少同資料庫互動的次數
    資料庫更適合處理批量操作,e.g.分頁查詢的時候,可以一次拉去很多條資料,分批進行返回,而不要分多次每次從資料庫中拉去一小部分資料

   9.使用IN代替OR, IN的值不要超過500個
    IN操作可以有效的使用到索引,而OR一般是用不到索引的。

   10.禁止使用order by rand()進行隨機排序
    rand()操縱會將所有的符合條件的資料載入到記憶體中進行排序,這樣會消耗大量的CPU和IO資源,我們可以在SQL查詢之前生成好隨機查詢的資料,然後執行SQL進行資料拉取

   11.WHERE從句中禁止對列進行函式轉換和計算
    對列進行函式轉換和計算,會導致無法使用索引,e.g. 當我們要查詢日期的時候,可能使用下面的語句進行查詢:
    where date(createTime) = '20180423' 這樣,我們便無法使用createTime上的索引,建議使用下面的語句:
    where createTime >= '20180423' and createTime < '20180423' 這樣就可以使用createTime的索引了

   12. UNION和UNION ALL的操作,可以合併兩個查詢的結果集
     當兩個結果集之間明顯沒有重複值的時候,儘量使用UNION ALL,這是因為UNION會將所有的資料放到一個臨時表中,然後進行去重操作

    13.拆分複雜的大SQL為多個小SQL進行查詢,再合併
      MySQL的一個SQL只能使用一個CPU進行計算,大SQL拆分之後可以通過並行的方式查詢,再合併多個結果集,從而提高查詢的效率。

六.資料庫操作行為規範
  1.超過100w行資料的寫操作,要分批進行
    大量的寫操作會造成嚴重的主從延時,造成資料庫操作的阻塞;分批進行可以有效的避免大事務操作
    對於大表結構的修改一定要使用pt-online-schema-change這樣的工具進行,使用這個工具進行大表結構修改的時候,會首先複製建立一個結構相同的新表,在這個新表的機構上進行修改,再將原表中的資料複製到新表中,同時在原表上新增一些觸發器,保證原表中新新增的資料能夠及時新增到新表中,在原表中資料全部複製完成之後,會在原表上新增一個很短的時間鎖,將新表的名稱命名為原表的名稱,並將原表刪除掉,這樣做可以避免大表修改產生的主從延遲的問題,避免在對錶欄位修改時產生的較長時間的鎖表問題。

  2.禁止為程式使用賬號授予super許可權
      MySQL在達到最大連結數之後,還允許1個具有super許可權的使用者進行連線,當為前端使用者授予super許可權之後,DBA處理賬號就無法再以super許可權進行登入排查問題了,在為程式連線賬號授予資料庫許可權時,應該遵循最小許可權的原則,並不能有類似drop table的許可權。