MYSQL資料庫 SQL開發設計規範
1編寫目的
本手冊是為指導開發人員按照文件中的規範進行MYSQL資料庫設計及SQL編碼。
2資料庫物件定義規範
2.1表的定義規則
2.1.1表名的規定
- 使用英語
命名應該使用英文單詞,避免使用拼音,特別不應該使用拼音簡寫;
命名不允許使用中文或者特殊字元,因為不是所有資料庫都支援;
只使用字母(A-Za-z),數字(0-9)以及下劃線(),不使用其他字元;
應該以字母開頭;
- 採用單數
表名使用的單詞,應是單數,而不是複數; 如工人表,選擇WORKER,
而不是WORKERS;
除非一些約定俗成的單詞,如SALES;
- 採用大寫
Mysql 大小寫轉換需要一定的開銷,要求資料庫配置為大小寫敏感,所以要求資料庫物件名稱建議一律大寫,也方便不同資料庫間的移植;
禁止使用大小寫混合的方式
- 單詞分隔
命名的各單詞之間可以使用下劃線(_) 進行分隔;
一般不要超過30個字元
- 表名的字首
一個專案或一個模組的表名定義建議字首最好統一,方便管理
2.1.2表的設計規則
-
如果沒有特殊要求,表的預設引擎採用Innodb,支援事務,鎖方式為行鎖,併發效能高。
-
每個表要求定義主鍵
-
平衡正規化與冗餘關係,效率優先;原則上表設計必須遵守第三正規化,如果因為合理的冗餘欄位將會給我們減少join的查詢除外;
-
單行記錄禁止超過8K
-
禁止使用外來鍵
-
單表列數目建議小於30
-
如果有可能,把表設計成固定長度的,可以提高效能。
-
索引並不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,索引最好不要超過5個
2.1.3列的規定
-
列名建議大寫
-
單詞采用單數
-
是否採用下劃線要統一
-
列名應避免二義性
關聯表中的同義字段列名應相同,一個應用程式中的多個關聯表,含有同樣含義的欄位,建議採用相同的列名,同時欄位名的資料型別也要求相同。
如客戶ID 一張表定義為CUSTOMER_ID 型別varchar
另一張表定義為CUSTOMER_NUM 型別int
如果兩張表依賴客戶ID欄位關聯查詢時,可能因為隱式轉換導致索引失效。
- 主鍵
一定要顯式定義主鍵
採用與業務無關的單獨列
建議採用自增列
資料型別採用int,並儘可能小,能用tinyint就不用int,能用int就不用bigint
將主鍵放在表的第一列
禁止使用varchar型別作為主鍵語句設計
不建議使用UUID型別設計主鍵,
首先UUID長度過長,另外InnoDB為聚集主鍵型別的引擎,資料會按照主鍵進行排序,由於UUID的無序性,InnoDB會產生巨大的IO壓力
- 索引列
索引列必須定義為not null,並設定default值
複合索引,選擇性高的欄位排在前面。
- 欄位
l 長度設計需要根據業務實際需要進行長度控制,禁止預留過長空間。例如status使用varchar(128)進行儲存
l 用盡量少的儲存空間來存數一個欄位的資料;
例如:能使用int就不要使用varchar、char,能用varchar(16)就不要varchar(256);
l IP地址最好使用int型別;
l 固定長度的型別最好使用char,例如:郵編;
l 能使用tinyint就不要使用smallint,int;
l 儘可能不用TEXT、 ofollow,noindex">BLOB 型別。
l 儲存年使用YEAR型別,儲存日期使用DATE型別,儲存時間(精確到秒)建議使用TIMESTAMP型別,因為TIMESTAMP使用4位元組,DATETIME使用8個位元組。
總之:Mysql的欄位選擇原則,資料越小,效能越高,請選擇合適欄位型別,mysql資料型別及範圍介紹見附錄4.2
2.1.4其它資料庫物件定義規則
除表外,其他物件命名也建議使用不同的字首來區別。建議如下:
檢視 v_
序列 seq_
簇 c_
觸發器 trg_
儲存過程 sp_/p_
函式 f_/fn_
主鍵 pk_
外來鍵 fk_
唯一索引 uk_
普通索引 idx_
說明:
1)為了避免不必要的衝突和麻煩,資料庫物件中不使用資料庫關鍵字和保留字,具體可閱附錄4.1
2)使用者自定義資料庫物件:表,檢視,主外來鍵,索引,觸發器,函式,儲存過程等風格要保持一致。
2.1.5建表格式規範
l 建表格式示範如下圖:

建表格式示範.png
l 修改及查看錶相關注釋語句如下:
1)修改表的註釋
alter table tablename comment '修改後的表的註釋';
如:alter table TB_EXAMPLE comment '示例表1';

修改表的註釋.png
2)修改欄位的註釋
alter table tablename modify column field_name int comment '修改後的欄位註釋';
注意:欄位名和欄位型別照寫就行
如:alter table TB_EXAMPLE modify APP_NAME varchar(255) not null default '' comment '應用名1';

欄位名和欄位型別修改.png
3) 查看錶註釋的方法
show create table tablename;
如:show create table TB_EXAMPLE;

查看錶註釋.png
4) 檢視欄位註釋的方法
show full columns from tablename;
如:show full columns from TB_EXAMPLE;

檢視欄位註釋.png
3MYSQL SQL開發規範
3.1SQL書寫規範
1、sql編寫時,大小寫一致
2、關鍵字單佔一行,如select、from、where、and、group by、order by等
3、注意行縮排和對齊,建議語句中的關鍵字右對齊
4、使用空格,SQL語句內的算術運算子、邏輯運算子(AND、OR、NOT)、 比較運算子(=、<=、>=、>、<、<>、BETWEEN AND)、IN、LIKE等運算子前後都應加一空格。
5、對較為複雜的sql語句加上註釋,說明演算法、功能。
註釋風格:註釋單獨成行、放在語句前面。
單行註釋:--
多行註釋:/* */
6、select後面的每一列(列數目大於1)單獨佔一行,where後面的每個條件(條件數大於1)單獨佔一行。
7、update set子句內容每一項單獨佔一行,無縮排。
8****、insert子句內容每個表字段單獨佔一行,無縮排;values每一項單獨佔一行,無縮排 。
3.2SQL開發技巧規範
-
Sql 語句儘可能得簡單
-
select * 儘量少用, 僅select出需要的欄位,只要一行資料時儘量使用limit 1
-
儘量避免在where子句中使用in,not in或者having,使用exists,not exists代替
-
儘量避免兩端模糊匹配 like %***%
-
儘量用union all代替union
-
拒絕大sql語句,大事物,大批量,避免鎖表, 拆分大的 DELETE 或 INSERT 語句
如果你有一個大的處理,一定把其拆分,使用 LIMIT 條件是一個好的方法。參考下面是一個示例:
程式碼如下:
while (1) {
//每次只做1000條
mysql_query("DELETE FROM logs WHERE log_date <= '2009-11-01' LIMIT 1000");
if (mysql_affected_rows() == 0) {
// 沒得可刪了,退出!
break;
}
// 每次都要休息一會兒
usleep(50000);
}
-
資料表最好起別名,便於sql優化器快速分析。
-
除非業務需要否則不允許在sql語句中使用order by 子句,禁止使用order by rand()
-
多表連線查詢
- 關聯表個數限制的基本原則
在報表資料庫或批處理資料庫中經常會有需要關聯多張表做查詢的操作,而這些表有的可能會是大表。過多的表做關聯可能給效能帶來嚴重的影響,請慎用關聯查詢。
如果不能滿足這個限定條件,可以考慮如下的兩種處理方式:
第一,增加 冗餘欄位 ,對於經常被關聯使用的個別欄位,可以考慮在一邊增加冗餘欄位的方式來減少關聯,這是一種反正規化化的處理方式,但經常被用於報表查詢型別的系統中。
第二,採用 中間結果表 方式。這種方式就是將原來一個SQL完成的操作拆開成多個SQL進行,將某兩張或三張表的關聯結果先取出,然後再拿結果集與剩下的表繼續做關聯,得到最終完整的結果。
2)連線語法
表連線分以下幾種方式
•等價連線(兩邊的表嚴格相等才返回)
A join B on 條件
•左外連線(左邊的表全返回,右邊表關聯不上就用null返回)
A left join B on條件
•右外連線(右邊的表全返回,左邊表關聯不上就用null返回)
A right join B on條件
•全外連線(左右兩表都不加限制,全部返回)
Afull join B and 條件
3)連線查詢的表字段前必須用表的別名標識。
如select a.col1,b.col2….
4)避免笛卡爾出現
產生笛卡爾連線的原因就是在多張表進行關聯的操作中缺少了表間的連線條件。由於笛卡爾積產生的結果集將是多表記錄的乘積關係,因此當哪怕只有一張表的記錄數比較大時,其結果集都將被數倍以上地放大,這勢必給資料庫效能帶來嚴重影響。所以在寫關聯語句時要嚴格檢查連線條件是否有遺漏。
5)join連線的欄位,欄位型別必須相同,防止隱式轉換導致的索引失效。
- 避免巢狀查詢
如:select a.name,(select b.address from table2 b where a.id=b.id) from a table1
用join代替:
Select a.name ,b.address
From table1 a
left join table2 b on a.id = b.id
- 能用連線查詢實現的子查詢,應避免使用子查詢
如:Select b.address from table1 b where a.id in(select id from table2 a where sex=1)
應改為:select b.address from table1 b , table2 a where b.id=a.id and a.sex=1
或者:
Select b.address
From table1 b
Inner join table2 a on b.id = a.id
Where a.sex=1
- Insert語句也要寫出欄位名稱,避免因表結構發生改變時發生編譯錯誤
如:insert into table (col1,col2,col3…) values(?,?,?...)
- 更新語句
查詢、更新語句中嚴格選擇所操作的欄位。
儘量減少表被訪問的次數,看下面這個SQL:
UPDATE tb_target a
SET a.col1=
(SELECT b.col1FROM tb_source b WHERE b.id = a.id),
a.col2 =
(SELECT b.col2 FROM tb_source b WHERE b.id = a.id),
a.col3 =
(SELECT b.col3 FROM tb_source b WHERE bid = a.id),
a.col4 =
(SELECT b.col4 FROM tb_source b WHERE b.id = a.id)
WHERE a.id IN (SELECT b.id FROM tb_source b)
該語句作用其實就是用更新一個表的多個列,但這樣寫會多次掃描源表。
如果改寫成如下的方式,則只需要掃描一次了:
UPDATE tb_target a
SET (a.col1,a.col2,a.col3,a.col4) =
(SELECT b.col1,b.col2,b.col3,b.col4
FROM tb_ source b
WHERE b.id = a.id)
WHERE EXISTS (SELECT 1 FROM tb_source b WHERE b.id = a.id)
- 減少控制語句的檢查次數
如在if…else語句中,儘可能最常用的,數量多的符合條件前置以被先檢查到,減少條件篩選的次數。
比如在人口清洗中,需要按民族分批處理時,最大數量符合條件的就是漢族,第一個處理
4附錄
4.1常用保留字列表
A
ACTION ADD ALL ALTER ANALYZE AND AS ASC ASENSITIVE
B
BEFORE BETWEEN BIGINT BINARY BIT BLOB BOTH BY
C
CALL CASCADE CASE CHANGE CHARCHARACTER COLLATE COLUMN CONDITION CONNECTION CONSTRAINT CONTINUE CONVERT CREATE CROSS CURRENT_DATE CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CHECK
D
DATABASE DATABASES DATE DAY_HOUR DAY_MICROSECOND DAY_MINUTE DAY_SECOND DEC DECIMAL DECLARE DEFAULT DELAYED DELETE DESC DESCRIBE DETERMINISTIC DISTINCT DISTINCTROW DIV DOUBLE DROP DUAL
E
EACH ELSE ELSEIF ENCLOSED ENUM ESCAPED EXISTS EXIT EXPLAIN
F
FALSE FETCH FLOAT FOR FORCE FOREIGN FORM FULLTEXT
G
GOTO GRANTGROUP
H
HAVING HIGH_PRIORITY HOUR_MICROSECOND HOUR_MINUTE HOUR_SECOND
I
IF IGNORE
IN
INDEX INFILE INNER INOUT INSENSITIVE INSERT INT INTEGER INTERVAL INTO IS ITERATE
J
JOIN
K
KEY KYES KILL
L
LEADING LEAVE LEFT LIKE LIMIT LINES LOAD LOCALTIME LOCALTIMESTAMP LOCK
LONG LONGBLOB LONGTEXT LOOP LOW_PRIORITY
M
MATCH MEDIUMBLOB MEDIUMINT MEDIUMTEXT MIDDLEINT MINUTE_MICROSECOND MINUTE_SECOND MOD MODIFIES
N
NATURAL NO NO_WRITE_TO_BINLOG NOT NULL NUMERIC
O
ON OPTIMIZE OPTION OPTIONALLY OR ORDER OUT OUTER OUTFILE
P
PRECISION PRIMARY PROCEDURE PURGE
R
READ READS REFERENCES REGEXP RELEASE RENAME REPEAT REPLACE REQUIRE RESTRICT
RETURN REVOKE RIGHT RLIKE REAL
S
SCHEMA SCHEMAS SECOND_MICROSECOND SELECT SENSITIVESEPARATOR SET SHOW SMALLINT SONAME SPATIAL SPECIFIC SQL SQL_BIG_RESULT SQL_CALC_FOUND_ROWS
SQL_SMALL_RESULT SQLEXCEPTION SQLSTATE SQLWARNING SSL STARTING STRAIGHT_JOIN
T
TABLE TERMINATED TEXT THEN TIME TIMESTAMP TINYBLOB TINYINT TINYTEXT TO
TRAILING TRIGGER TRUE
U
UNDO UNION UNIQUE UNLOCK UNSIGNED UPDATE USAGE USE USING UTC_DATE UTC_TIME UTC_TIMESTAMP
V
VALUES VARBINARY VARCHAR VARCHARACTER VARYING
W
WHEN WHERE WHILE WITH WRITE
X
XOR
Y
YEAR_MONTH
Z
ZEROFILL
4.2Mysql資料型別介紹
4.2.1數字型別列表

數字型別列表.png
4.2.2日期型別列表

日期型別列表.png
4.2.3字元型別列表

字元型別列表.png