MySQL學習筆記_資料庫設計規範
阿新 • • 發佈:2019-01-02
資料庫設計的規範:
一.資料庫命名規範
二.資料庫基本設計規範
三.資料庫索引設計規範
四.資料庫欄位設計規範
五.資料庫SQl開發規範
六.資料庫操作行為規範
這是因為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的許可權。
一.資料庫命名規範
二.資料庫基本設計規範
三.資料庫索引設計規範
四.資料庫欄位設計規範
五.資料庫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的許可權。