1. 程式人生 > >收集整理mysql資料庫設計規範與原則

收集整理mysql資料庫設計規範與原則

1、 資料庫命名規範

 採用26個英文字母(區分大小寫)和0-9的自然數(經常不需要)加上下劃線'_'組成;命名簡潔明確(長度不能超過30個字元);例如:user, stat, log, 也可以wifi_user, wifi_stat, wifi_log給資料庫加個字首;除非是備份資料庫可以加0-9的自然數:user_db_20151210;           

2、 資料庫表名命名規範

採用26個英文字母(區分大小寫)和0-9的自然數(經常不需要)加上下劃線'_'組成;命名簡潔明確,多個單詞用下劃線'_'分隔;例如:user_login,user_profile,user_detail,user_role, user_role_relation,user_role_right, user_role_right_relation表字首'user_'可以有效的把相同關係的表顯示在一起;           

3、 資料庫表字段名命名規範

 採用26個英文字母(區分大小寫)和0-9的自然數(經常不需要)加上下劃線'_'組成;命名簡潔明確,多個單詞用下劃線'_'分隔;例如:user_login表字段 user_id, user_name, pass_word, eamil, tickit, status, mobile, add_time預設系統時間;

表與表之間的相關聯欄位名稱要求儘可能的相同; 如 web_user 表裡面的 userId 和 web_group 表裡面的 userId 相對應.

當欄位型別為列舉或者布林型時,使用 CHAR(1)(或者CHAR(2))型別,填寫預設值,狀態欄位的預設值不能為null一般是設定成0或者-1,狀態欄位的描述寫成 comment '團購券狀態:1.已購買;2.已使用;3.退款中;4已退款'。

在設計時候儘量包含日期欄位:CREATE_DATE(建立日期),UPDATE_DATE(更新日期)等。

mysql中對日期約定一種錄入方式,如'2014-12-31 00:00:00.0'.

預設值,數字型別預設值為0,字串預設值為’’,日期預設值為'1900-01-01 00:00:00.0'

4、 資料庫表字段型別規範

用盡量少的儲存空間來存數一個欄位的資料;例如:能使用int就不要使用varchar、char,能用varchar(16)就不要使用varchar(256); IP地址最好使用int型別;固定長度的型別最好使用char,例如:郵編;能使用tinyint就不要使用smallint,int;最好給每個欄位一個預設值,最好不能為null;       

5、 資料庫表索引規範

命名簡潔明確,例如:user_login表user_name欄位的索引應為user_name_index唯一索引;為每個表建立一個主鍵索引;為每個表建立合理的索引;建立複合索引請慎重;

值範圍重複的比例少的,建立索引欄位,比如  CREATE_DATE(錄入時間)欄位;值範圍重複比率的欄位不需要建立索引比如IS_RETURN(是否已退款)欄位

WHERE條件後面的經常查詢的欄位,需要加索引,比如ORDER_GOODS 表的ORDER_SN(商品號)等          

6、 簡單熟悉資料庫正規化

第一正規化(1NF):欄位值具有原子性,不能再分(所有關係型資料庫系統都滿足第一正規化);例如:姓名欄位,其中姓和名是一個整體,如果區分姓和名那麼必須設立兩個獨立欄位;

第二正規化(2NF):一個表必須有主鍵,即每行資料都能被唯一的區分;備註:必須先滿足第一正規化;

第三正規化(3NF):一個表中不能包涵其他相關表中非關鍵欄位的資訊,即資料表不能有沉餘字段;備註:必須先滿足第二正規化;

備註:往往我們在設計表中不能遵守第三正規化,因為合理的沉餘字段將會給我們減少join的查詢;例如:相簿表中會新增圖片的點選數字段,在相簿圖片表中也會新增圖片的點選數字段;

7、 MYSQL資料庫設計原則              

a)     核心原則:

u  不在資料庫做運算;

u  cpu計算務必移至業務層;

u  控制列數量(欄位少而精,欄位數建議在20以內);

u  平衡正規化與冗餘(效率優先;往往犧牲正規化)

u  拒絕3B(拒絕大sql語句:big sql、拒絕大事物:big transaction、拒絕大批量:big batch);

b)     欄位類原則

u  用好數值型別(用合適的欄位型別節約空間);

u  字元轉化為數字(能轉化的最好轉化,同樣節約空間、提高查詢效能);

u  避免使用NULL欄位(NULL欄位很難查詢優化、NULL欄位的索引需要額外空間、NULL欄位的複合索引無效);

u  少用text型別(儘量使用varchar代替text欄位);

c)     索引類原則

u  合理使用索引(改善查詢,減慢更新,索引一定不是越多越好);

u  字元欄位必須建字首索引;

u  不在索引做列運算;

u  innodb主鍵推薦使用自增列(主鍵建立聚簇索引,主鍵不應該被修改,字串不應該做主鍵)(理解Innodb的索引儲存結構就知道了);

u  不用外來鍵(由程式保證約束);

d)     sql類原則

u  sql語句儘可能簡單(一條sql只能在一個cpu運算,大語句拆小語句,減少鎖時間,一條大sql可以堵死整個庫);

u  寫到應用程式的SQL語句,禁止一切DDL操作,例如:create,drop,alter,grant,remove;如有特殊需要,請與dba協商同意方可使用

u  當表連線時候,用於連線的兩個表的欄位如果資料型別不一致,則必須在一邊加上型別轉換的函式。杜絕mysql做隱式型別轉換的情況

u  避免在where字句中對欄位施加函式,如果是業務要求的除外,但需要在編寫時候諮詢DBA比如DATE_FORMAT(p.PAYMENT_DATE, '%Y-%m-%d') >= DATE_FORMAT('2014-10-01', '%Y-%m-%d'),就需要改正掉

u  簡單的事務;

u  避免使用trig/func(觸發器、函式不用客戶端程式取而代之);

u  不用select *(消耗cpu,io,記憶體,頻寬,這種程式不具有擴充套件性);

u  OR改寫為IN(or的效率是n級別);

u  OR改寫為UNION(mysql的索引合併很弱智);

                            select id from t where phone = ’159′ or name = ‘john’;

                             =>

                           select id from t where phone=’159′

                        union

                      select id from t where name=’jonh’

u  避免負向%;

u  慎用count(*);

u  limit高效分頁(limit越大,效率越低);

u  使用union all替代union(union有去重開銷);

u  少用連線join;

u  使用group by;

u  請使用同類型比較;

u  打散批量更新;

1、應儘量避免在 where 子句中使用!=或<>操作符,否則引擎將放棄使用索引而進行全表掃描。

2、對查詢進行優化,應儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。

3、應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描。如:

select id from t where num is null

可以在num上設定預設值0,確保表中num列沒有null值,然後這樣查詢:

select id from t where num=0

4、儘量避免在 where 子句中使用 or 來連線條件,否則將導致引擎放棄使用索引而進行全表掃描,如:

select id from t where num=10 or num=20

可以這樣查詢:

select id from t where num=10

union all

select id from t where num=20

5、下面的查詢也將導致全表掃描:(不能前置百分號)

select id from t where name like ‘%c%’

下面走索引

select id from t where name like ‘c%’

若要提高效率,可以考慮全文檢索。

6、in 和 not in 也要慎用,否則會導致全表掃描,如:

select id from t where num in(1,2,3)

對於連續的數值,能用 between 就不要用 in 了:

select id from t where num between 1 and 3

7、如果在 where 子句中使用引數,也會導致全表掃描。因為SQL只有在執行時才會解析區域性變數,但優化程式不能將訪問計劃的選擇推遲到執行時;它必須在編譯時進行選擇。然 而,如果在編譯時建立訪問計劃,變數的值還是未知的,因而無法作為索引選擇的輸入項。如下面語句將進行全表掃描:

select id from t where [email protected]

可以改為強制查詢使用索引:

select id from t with(index(索引名)) where [email protected]

8、應儘量避免在 where 子句中對欄位進行表示式操作,這將導致引擎放棄使用索引而進行全表掃描。如:

select id from t where num/2=100

應改為:

select id from t where num=100*2

9、應儘量避免在where子句中對欄位進行函式操作,這將導致引擎放棄使用索引而進行全表掃描。如:

select id from t where substring(name,1,3)=’abc’ –name以abc開頭的id

select id from t where datediff(day,createdate,’2005-11-30′)=0 –’2005-11-30′生成的id

應改為:

select id from t where name like ‘abc%’

select id from t where createdate>=’2005-11-30′ and createdate<’2005-12-1′

10、不要在 where 子句中的“=”左邊進行函式、算術運算或其他表示式運算,否則系統將可能無法正確使用索引。

11、在使用索引欄位作為條件時,如果該索引是複合索引,那麼必須使用到該索引中的第一個欄位作為條件時才能保證系統使用該索引,否則該索引將不會被使 用,並且應儘可能的讓欄位順序與索引順序相一致。

12、不要寫一些沒有意義的查詢,如需要生成一個空表結構:

select col1,col2 into #t from t where 1=0

這類程式碼不會返回任何結果集,但是會消耗系統資源的,應改成這樣:

create table #t(…)

13、很多時候用 exists 代替 in 是一個好的選擇:

select num from a where num in(select num from b)

用下面的語句替換:

select num from a where exists(select 1 from b where num=a.num)

14、並不是所有索引對查詢都有效,SQL是根據表中資料來進行查詢優化的,當索引列有大量資料重複時,SQL查詢可能不會去利用索引,如一表中有欄位 sex,male、female幾乎各一半,那麼即使在sex上建了索引也對查詢效率起不了作用。

15、索引並不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數較好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有 必要。

16.應儘可能的避免更新 clustered 索引資料列,因為 clustered 索引資料列的順序就是表記錄的物理儲存順序,一旦該列值改變將導致整個表記錄的順序的調整,會耗費相當大的資源。若應用系統需要頻繁更新 clustered 索引資料列,那麼需要考慮是否應將該索引建為 clustered 索引。

17、儘量使用數字型欄位,若只含數值資訊的欄位儘量不要設計為字元型,這會降低查詢和連線的效能,並會增加儲存開銷。這是因為引擎在處理查詢和連線時會 逐個比較字串中每一個字元,而對於數字型而言只需要比較一次就夠了。

18、儘可能的使用 varchar/nvarchar 代替 char/nchar ,因為首先變長欄位儲存空間小,可以節省儲存空間,其次對於查詢來說,在一個相對較小的欄位內搜尋效率顯然要高些。

19、任何地方都不要使用 select * from t ,用具體的欄位列表代替“*”,不要返回用不到的任何欄位。

20、儘量使用表變數來代替臨時表。如果表變數包含大量資料,請注意索引非常有限(只有主鍵索引)。

21、避免頻繁建立和刪除臨時表,以減少系統表資源的消耗。

22、臨時表並不是不可使用,適當地使用它們可以使某些例程更有效,例如,當需要重複引用大型表或常用表中的某個資料集時。但是,對於一次性事件,較好使 用匯出表。

23、在新建臨時表時,如果一次性插入資料量很大,那麼可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果資料量不大,為了緩和系統表的資源,應先create table,然後insert。

24、如果使用到了臨時表,在儲存過程的最後務必將所有的臨時表顯式刪除,先 truncate table ,然後 drop table ,這樣可以避免系統表的較長時間鎖定。

25、儘量避免使用遊標,因為遊標的效率較差,如果遊標操作的資料超過1萬行,那麼就應該考慮改寫。

26、使用基於遊標的方法或臨時表方法之前,應先尋找基於集的解決方案來解決問題,基於集的方法通常更有效。

27、與臨時表一樣,遊標並不是不可使用。對小型資料集使用 FAST_FORWARD 遊標通常要優於其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的資料時。在結果集中包括“合計”的例程通常要比使用遊標執行的速度快。如果開發時 間允許,基於遊標的方法和基於集的方法都可以嘗試一下,看哪一種方法的效果更好。

28、在所有的儲存過程和觸發器的開始處設定 SET NOCOUNT ON ,在結束時設定 SET NOCOUNT OFF 。無需在執行儲存過程和觸發器的每個語句後向客戶端傳送 DONEINPROC 訊息。

29、儘量避免向客戶端返回大資料量,若資料量過大,應該考慮相應需求是否合理。

30、儘量避免大事務操作,提高系統併發能力。

e)     效能分析工具

       show profile;

         mysqlsla;

         mysqldumpslow;

         explain;

         show slow log;

         show processlist;