mysql開發正規化和原則
一、 表設計
- 庫名、表名、欄位名必須使用小寫字母,“_”分割。
- 庫名、表名、欄位名必須不超過12個字元。
- 庫名、表名、欄位名見名知意,建議使用名詞而不是動詞。
- 建議使用InnoDB儲存引擎。
- 儲存精確浮點數必須使用DECIMAL替代FLOAT和DOUBLE。
- 建議使用UNSIGNED儲存非負數值。
- 建議使用INT UNSIGNED儲存IPV4。
- 整形定義中不新增長度,比如使用INT,而不是INT(4)。
- 使用短資料型別,比如取值範圍為0-80時,使用TINYINT UNSIGNED。
- 不建議使用ENUM型別,使用TINYINT來代替。
- 儘可能不使用TEXT、BLOB型別。
- VARCHAR(N),N表示的是字元數不是位元組數,比如VARCHAR(255),可以最大可儲存255個漢字,需要根據實際的寬度來選擇N。
- VARCHAR(N),N儘可能小,因為MySQL一個表中所有的VARCHAR欄位最大長度是65535個位元組,進行排序和建立臨時表一類的記憶體操作時,會使用N的長度申請記憶體。
- 表字符集選擇UTF8。
- 使用VARBINARY儲存變長字串。
- 儲存年使用YEAR型別。
- 儲存日期使用DATE型別。
- 儲存時間(精確到秒)建議使用TIMESTAMP型別,因為TIMESTAMP使用4位元組,DATETIME使用8個位元組。
- 建議欄位定義為NOT NULL。
- 將過大欄位拆分到其他表中。
- 禁止在資料庫中使用VARBINARY、BLOB儲存圖片、檔案等。
- 表結構變更需要通知DBA稽核。
二、 索引
- 非唯一索引必須按照“idx_欄位名稱_欄位名稱[_欄位名]”進行命名。
- 唯一索引必須按照“uniq_欄位名稱_欄位名稱[_欄位名]”進行命名。
- 索引名稱必須使用小寫。
- 索引中的欄位數建議不超過5個。
- 單張表的索引數量控制在5個以內。
- 唯一鍵由3個以下欄位組成,並且欄位都是整形時,使用唯一鍵作為主鍵。
- 沒有唯一鍵或者唯一鍵不符合5中的條件時,使用自增(或者通過發號器獲取)id作為主鍵。
- 唯一鍵不和主鍵重複。
- 索引欄位的順序需要考慮欄位值去重之後的個數,個數多的放在前面。
- ORDER BY,GROUP BY,DISTINCT的欄位需要新增在索引的後面。
- 使用EXPLAIN判斷SQL語句是否合理使用索引,儘量避免extra列出現:Using File Sort,UsingTemporary。
- UPDATE、DELETE語句需要根據WHERE條件新增索引。
- 不建議使用%字首模糊查詢,例如LIKE “%weibo”。
- 對長度過長的VARCHAR欄位建立索引時,新增crc32或者MD5 Hash欄位,對Hash欄位建立索引。
- 合理建立聯合索引(避免冗餘),(a,b,c) 相當於 (a) 、(a,b) 、(a,b,c)。
- 合理利用覆蓋索引。
- SQL變更需要確認索引是否需要變更並通知DBA。
三、 SQL語句
- 使用prepared statement,可以提供效能並且避免SQL注入。
- SQL語句中IN包含的值不應過多。
- UPDATE、DELETE語句不使用LIMIT。
- WHERE條件中必須使用合適的型別,避免MySQL進行隱式型別轉化。
- SELECT語句只獲取需要的欄位。
- SELECT、INSERT語句必須顯式的指明欄位名稱,不使用SELECT *,不使用INSERTINTO table()。
- 使 用SELECT column_name1, column_name2 FROM table WHERE[condition]而不是SELECT column_name1 FROM table WHERE[condition]和SELECT column_name2 FROM table WHERE [condition]。
- WHERE條件中的非等值條件(IN、BETWEEN、<、<=、>、>=)會導致後面的條件使用不了索引。
- 避免在SQL語句進行數學運算或者函式運算,容易將業務邏輯和DB耦合在一起。
- INSERT語句使用batch提交(INSERT INTO tableVALUES(),(),()……),values的個數不應過多。
- 避免使用儲存過程、觸發器、函式等,容易將業務邏輯和DB耦合在一起,並且MySQL的儲存過程、觸發器、函式中存在一定的bug。
- 避免使用JOIN。
- 使用合理的SQL語句減少與資料庫的互動次數。
- 不使用ORDER BY RAND(),使用其他方法替換。
- 建議使用合理的分頁方式以提高分頁的效率。
- 統計表中記錄數時使用COUNT(*),而不是COUNT(primary_key)和COUNT(1)。
- 禁止在從庫上執行後臺管理和統計型別功能的QUERY。
四、 散表
- 每張表資料量建議控制在5000w以下。
- 可以結合使用hash、range、lookup table進行散表。
- 散表如果使用md5(或者類似的hash演算法)進行散表,表名字尾使用16進位制,比如user_ff。
- 推薦使用CRC32求餘(或者類似的算術演算法)進行散表,表名字尾使用數字,數字必須從0開始並等寬,比如散100張表,字尾從00-99。
- 使用時間散表,表名字尾必須使用特定格式,比如按日散表user_20110209、按月散表user_201102。
五、 其他
- 批量匯入、匯出資料需要DBA進行審查,並在執行過程中觀察服務。
- 批量更新資料,如update,delete 操作,需要DBA進行審查,並在執行過程中觀察服務。
- 產品出現非資料庫平臺運維導致的問題和故障時,如前端被抓站,請及時通知DBA,便於維護服務穩定。
- 業務部門程式出現bug等影響資料庫服務的問題,請及時通知DBA,便於維護服務穩定。
- 業務部門推廣活動,請提前通知DBA進行服務和訪問評估。
- 如果出現業務部門人為誤操作導致資料丟失,需要恢復資料,請在第一時間通知DBA,並提供準確時間,誤操作語句等重要線索。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
FAQ
1-1.庫名、表名、欄位名必須使用小寫字母,“_”分割。
a)MySQL有配置引數lower_case_table_names,不可動態更改,linux系統預設為0,即庫表名以實際情況儲存,大小寫敏感。如果是1,以小寫儲存,大小寫不敏感。如果是2,以實際情況儲存,但以小寫比較。
b) 如果大小寫混合用,可能存在abc,Abc,ABC等多個表共存,容易導致混亂。
c) 欄位名顯示區分大小寫,但實際使用不區分,即不可以建立兩個名字一樣但大小寫不一樣的欄位。
d) 為了統一規範, 庫名、表名、欄位名使用小寫字母。
1-2.庫名、表名、欄位名必須不超過12個字元。
庫名、表名、欄位名支援最多64個字元,但為了統一規範、易於辨識以及減少傳輸量,必須不超過12字元。
1-3.庫名、表名、欄位名見名知意,建議使用名詞而不是動詞。
a) 使用者評論可用表名usercomment或者comment。
b) 庫表是一種客觀存在的事物,一種物件,所以建議使用名詞。
1-4.建議使用InnoDB儲存引擎。
a) 5.5以後的預設引擘,支援事務,行級鎖,更好的恢復性,高併發下效能更好,對多核,大記憶體,ssd等硬體支援更好。
b) 具體比較可見附件的官方白皮書。
1-5.儲存精確浮點數必須使用DECIMAL替代FLOAT和DOUBLE。
a) mysql中的數值型別(不包括整型):
IEEE754浮點數:float (單精度)
, double 或real (雙精度)
定點數: decimal或 numeric
單精度浮點數的有效數字二進位制是24位,按十進位制來說,是8位;雙精度浮點數的有效數字二進位制是53位,按十進位制來說,是16
位
一個實數的有效數字超過8位,用單精度浮點數來表示的話,就會產生誤差!同樣,如果一個實數的有效數字超過16位,用雙精度浮點數來表示,也會產生誤差
b)IEEE754標準的計算機浮點數,在內部是用二進位制表示的,但在將一個十進位制數轉換為二進位制浮點數時,也會造成誤差,原因是不是所有的數都能轉換成有限長度的二進位制數。
即一個二進位制可以準確轉換成十進位制,但一個帶小數的十進位制不一定能夠準確地用二進位制來表示。
例項:
drop table if exists t;
create table t(value float(10,2));
insert into t values(131072.67),(131072.68);
select value from t;
+-----------+
|value |
+-----------+
| 131072.67 |
| 131072.69 |
+-----------+
1-6.建議使用UNSIGNED儲存非負數值。
同樣的位元組數,儲存的數值範圍更大。如tinyint 有符號為 -128-127,無符號為0-255
1-7. 如何使用INT UNSIGNED儲存ip?
使用INTUNSIGNED而不是char(15)來儲存ipv4地址,通過MySQL函式inet_ntoa和inet_aton來進行轉化。Ipv6地址目前沒有轉化函式,需要使用DECIMAL或者兩個bigINT來儲存。例如:
SELECT INET_ATON('209.207.224.40');
3520061480
SELECT INET_NTOA(3520061480);
209.207.224.40
1-8. INT[M],M值代表什麼含義?
注意數值型別括號後面的數字只是表示寬度而跟儲存範圍沒有關係,比如INT(3)預設顯示3位,空格補齊,超出時正常顯示,Python、Java客戶端等不具備這個功能。
1-10.不建議使用ENUM、SET型別,使用TINYINT來代替。
a)ENUM,有三個問題:新增新的值要做DDL,預設值問題(將一個非法值插入ENUM(也就是說,允許的值列之外的字串),將插入空字串以作為特殊錯誤值),索引值問題(插入數字實際是插入索引對應的值)
例項:
drop table if exists t;
create table t(sex enum('0','1'));
insert into t values(1);
insert into t values('3');
select * from t;
+------+
| sex |
+------+
| 0 |
| |
+------+
2 rows in set (0.00 sec)
1-11.儘可能不使用TEXT、BLOB型別。
a) 索引排序問題,只能使用max_sort_length的長度或者手工指定ORDER BY SUBSTRING(column,length)的長度來排序
b) Memory引擘不支援text,blog型別,會在磁碟上生成臨時表
c) 可能浪費更多的空間
d) 可能無法使用adaptive hash index
e) 導致使用where沒有索引的語句變慢
1-13. VARCHAR中會產生額外儲存嗎?
VARCHAR(M),如果M<256時會使用一個位元組來儲存長度,如果M>=256則使用兩個位元組來儲存長度。
1-14.表字符集選擇UTF8。
a) 使用utf8字符集,如果是漢字,佔3個位元組,但ASCII碼字元還是1個位元組。
b) 統一,不會有轉換產生亂碼風險
c) 其他地區的使用者(美國、印度、臺灣)無需安裝簡體中文支援,就能正常看您的文字,並且不會出現亂碼
d)ISO-8859-1編碼(latin1)使用了單位元組內的所有空間,在支援ISO-8859-1的系統中傳輸和儲存其他任何編碼的位元組流都不會被拋棄。即把其他任何編碼的位元組流當作ISO-8859-1編碼看待都沒有問題,儲存的是原封不動的位元組流。
1-15.使用VARBINARY儲存變長字串。
二進位制位元組流,不存在編碼問題
1-18. 為什麼建議使用TIMESTAMP來儲存時間而不是DATETIME?
DATETIME和TIMESTAMP都是精確到秒,優先選擇TIMESTAMP,因為TIMESTAMP只有4個位元組,而DATETIME8個位元組。同時TIMESTAMP具有自動賦值以及自動更新的特性。
如何使用TIMESTAMP的自動賦值屬性?
a) 將當前時間作為ts的預設值:ts TIMESTAMP DEFAULTCURRENT_TIMESTAMP。
b) 當行更新時,更新ts的值:ts TIMESTAMP DEFAULT 0 ONUPDATE CURRENT_TIMESTAMP。
c) 可以將1和2結合起來:ts TIMESTAMP DEFAULTCURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP。
1-19.建議欄位定義為NOT NULL。
a)如果null欄位被索引,需要額外的1位元組
b)使索引,索引統計,值的比較變得更復雜
c)可用0,''代替
d)如果是索引欄位,一定要定義為not null
1-21.禁止在資料庫中使用VARBINARY、BLOB儲存圖片、檔案等。
採用分散式檔案系統更高效
2. 為什麼MySQL的效能依賴於索引?
MySQL的查詢速度依賴良好的索引設計,因此索引對於高效能至關重要。合理的索引會加快查詢速度(包括UPDATE和DELETE的速度,MySQL會將包含該行的page載入到記憶體中,然後進行UPDATE或者DELETE操作),不合理的索引會降低速度。
MySQL索引查詢類似於新華字典的拼音和部首查詢,當拼音和部首索引不存在時,只能通過一頁一頁的翻頁來查詢。當MySQL查詢不能使用索引時,MySQL會進行全表掃描,會消耗大量的IO。
2-5. 為什麼一張表中不能存在過多的索引?
InnoDB的secondaryindex使用b+tree來儲存,因此在UPDATE、DELETE、INSERT的時候需要對b+tree進行調整,過多的索引會減慢更新的速度。
2-11. EXPLAIN語句
EXPLAIN語句(在MySQL客戶端中執行)可以獲得MySQL如何執行SELECT語句的資訊。通過對SELECT語句執行EXPLAIN,可以知曉MySQL執行該SELECT語句時是否使用了索引、全表掃描、臨時表、排序等資訊。儘量避免MySQL進行全表掃描、使用臨時表、排序等。詳見官方文件。
2-13.不建議使用%字首模糊查詢,例如LIKE “%weibo”。
會導致全表掃描
2-14. 如何對長度大於50的VARCHAR欄位建立索引?
下面的表增加一列url_crc32,然後對url_crc32建立索引,減少索引欄位的長度,提高效率。
- CREATE TABLE url(
……
url
VARCHAR(255) NOT NULL DEFAULT 0,
url_crc32INT
UNSIGNED NOT NULL DEFAULT 0,
……
index idx_url(url_crc32)
)
2-16. 什麼是覆蓋索引?
InnoDB 儲存引擎中,secondaryindex(非主鍵索引)中沒有直接儲存行地址,儲存主鍵值。如果使用者需要查詢secondaryindex中所不包含的資料列時,需要先通過secondaryindex查詢到主鍵值,然後再通過主鍵查詢到其他資料列,因此需要查詢兩次。
覆蓋索引的概念就是查詢可以通過在一個索引中完成,覆蓋索引效率會比較高,主鍵查詢是天然的覆蓋索引。
合理的建立索引以及合理的使用查詢語句,當使用到覆蓋索引時可以獲得性能提升。
比如SELECT email,uid FROM user_email WHEREuid=xx,如果uid不是主鍵,適當時候可以將索引新增為index(uid,email),以獲得性能提升。
3-3.UPDATE、DELETE語句不使用LIMIT。
a) 可能導致主從資料不一致
b) 會記錄到錯誤日誌,導致日誌佔用大量空間
3-4. 為什麼需要避免MySQL進行隱式型別轉化?
因為MySQL進行隱式型別轉化之後,可能會將索引欄位型別轉化成=號右邊值的型別,導致使用不到索引,原因和避免在索引欄位中使用函式是類似的。
3-6. 為什麼不建議使用SELECT *?
增加很多不必要的消耗(cpu、io、記憶體、網路頻寬);增加了使用覆蓋索引的可能性;當表結構發生改變時,前段也需要更新。
3-13. 如何減少與資料庫的互動次數?
使用下面的語句來減少和db的互動次數:
INSERT ... ON DUPLICATE KEY UPDATE
REPLACE
INSERT IGNORE
INSERT INTO values(),()如何結合使用多個緯度進行散表散庫?
例如微博message,先按照crc32(message_id)將message散到16個庫中,然後針對每個庫中的表,一天生成一張新表。
3-14. 為什麼不能使用ORDER BY rand()?
因為ORDER BYrand()會將資料從磁碟中讀取,進行排序,會消耗大量的IO和CPU,可以在程式中獲取一個rand值,然後通過在從資料庫中獲取對應的值。
3-15. MySQL中如何進行分頁?
假如有類似下面分頁語句:
SELECT * FROM table ORDER BY TIME DESC LIMIT 10000,10;
這種分頁方式會導致大量的io,因為MySQL使用的是提前讀取策略。
推薦分頁方式:
SELECT * FROM table WHERE TIME<last_TIME ORDER BYTIME DESC LIMIT 10.
SELECT * FROM table inner JOIN(SELECT id FROM table ORDER BYTIME LIMIT 10000,10) as t USING(id)
3-17.為什麼避免使用複雜的SQL?
拒絕使用複雜的SQL,將大的SQL拆分成多條簡單SQL分步執行。原因:簡單的SQL容易使用到MySQL的querycache;減少鎖表時間特別是MyISAM;可以使用多核cpu。
2. InnoDB儲存引擎為什麼避免使用COUNT(*)?
InnoDB表避免使用COUNT(*)操作,計數統計實時要求較強可以使用memcache或者redis,非實時統計可以使用單獨統計表,定時更新。
相關推薦
mysql開發正規化和原則
一、 表設計 庫名、表名、欄位名必須使用小寫字母,“_”分割。庫名、表名、欄位名必須不超過12個字元。庫名、表名、欄位名見名知意,建議使用名詞而不是動詞。建議使用InnoDB儲存引擎。儲存精確浮點數必須使用DECIMAL替代FLOAT和DOUBLE。建議使用UNSIGNE
mysql 開發基礎系列15 索引的設計和使用
hash索引 drop myisam mar 至少 不同類 不同 執行 例如 一.概述 所有mysql 列類型都可以被索引,是提高select查詢性能的最佳方法。 根據存儲引擎可以定義每個表的最大索引數和最大索引長度,每種引擎對每個表至少支持16個索引,總索引長度至少為
Kubernetes設計和開發四大基本原則
作者介紹:Saad Ali 是來自Google的高階軟體工程師,致力於開源Kubernetes專案。他於2014年12加入該專案並負責Kubernetes儲存和volume子系統的開發。他還擔任Kubernetes儲存興趣小組的負責人,同時也是CSI(容器儲存介面)的協同開發者和maint
手把手教你做jsp servlet mysql實現的圖書管理系統附帶視訊開發教程和完整原始碼
上一個教程我們做的是對資料庫框架底層原理的講解,然後教大家做了一個自己的資料庫框架,這次我們做的這個圖書管理系統就是用我們上個教程自己寫的資料庫框架,整個專案做完框架執行的很穩定,沒有出現任何問題。如果你還沒有學習我們的那個資料庫框架教程的話我建議你還是先去學習那個資料庫框架的教程,地址是:ht
《敏捷軟體開發》-方法論要素和原則
方法論的英文為Methodology,程式設計的方法論應該是指軟體開發的一整套方法、過程、規則、實踐、技術。不過我們一般提到的方法論都偏重於專案、過程和人員。《敏捷軟體開發》的作者Alistair Cockburn提出方法論具有以下要素:角色、個性、技能、團隊、技術、活動、過程、產品、里程碑、標準、
MySQL資料庫三大正規化和反正規化
第一正規化(1NF): 資料表中的每一列(欄位),必須是不可拆分的最小單元,也就是確保每一列的原子性。 Table: t_user_info — — — — — —
mysql 開發進階篇系列 43 邏輯備份與恢復(基於時間和位置的不完全恢復)
一. 概述 在上篇講到了邏輯備份,使用mysqldump工具來備份一個庫,並使用完全恢復還原了資料庫。在結尾也講到了誤操作是不能用完全恢復的。解決辦法是:我們需要恢復到誤操作之前的狀態,然後跳過誤操作語句。再恢復後面執行的語句,完成我們的恢復,這種恢復叫“不完全恢復”。在mysql 中,不完
PHP+MySQL開發小專案的集合筆記(四)控制div的排列和p標籤,從另外表讀取加工資料並規定小數點位數
需求:HTML頁面增加註釋,div盒子控制曲線大小,多個盒子相互巢狀。具體資料從另外表內獲取。 HTML頁面更改: <!-- Morris chart - Sales --> <!-- Change! -->
mysql 開發進階篇系列 45 xtrabackup 安裝與使用者許可權說明(系統使用者和mysql使用者)
一. 安裝說明 安裝XtraBackup 2.4 版本有三種方式: (1) 儲存庫安裝Percona XtraBackup(推薦) (2 )下載的rpm或apt包安裝Percona XtraBackup。 (3) 原始碼編譯和安裝。 Pe
【轉】敏捷開發技術的特點、優勢和原則
敏捷開發(agile development)是一種以人為核心、迭代、循序漸進的開發方法。在敏捷開發中,軟體專案的構建被切分成多個子專案,各個子專案的成果都經過測試,具備整合和可執行的特徵。簡言之,就是把一個大專案分為多個相互聯絡,但也可獨立執行的小專案,並分別完成,在此過程
軟體開發的原理和原則
軟體危機“ 軟體危機是指軟體開發和維護過程中遇到的嚴重的問題 表現 產品不符合客戶的實際需求 軟體質量差 文件不合格 價格昂貴 產生的原因 軟體的特點給開發和維護帶來的困難 開發管理人員只重視開發不注意維護 軟體開發遵循的原理: (1)用分階段的生存週期計劃嚴格管理 (2)堅持進行階
java開發之提高java和mysql程式碼效能和質量
if巢狀的層數最好不要超過3層 /* * 巢狀太多層if,閱讀性非常差,和看遞迴程式碼一樣 * @author yifangyou * @since 2011-08-16 09:35:00 */ int exampl
階段4:手把手教你做一個jsp servlet mysql實現的學生成績管理系統附帶視訊開發教程和完整原始碼
繼前段時間我出了四個階段的Java swing的學生資訊系統後,大家反響不錯,所以緊接著就開始錄製Java web的學生系統,還是跟以前一樣,分為四個階段,每個階段都是獨立完整的系統,第一階段實現的功能是基本的學生資訊管理功能,目前第一階段、第二階段、第三階段、第四階段已經全
階段1:手把手教你做一個jsp servlet mysql實現的學生資訊管理系統附帶視訊開發教程和完整原始碼
繼前段時間我出了四個階段的Java swing的學生資訊系統後,大家反響不錯,所以緊接著就開始錄製Java web的學生系統,還是跟以前一樣,分為四個階段,每個階段都是獨立完整的系統,第一階段實現的功能是基本的學生資訊管理功能,包括學生資訊的新增、修改、刪除、查詢,班級資訊的
階段3:手把手教你做一個jsp servlet mysql實現的學生簽到考勤請假管理系統附帶視訊開發教程和完整原始碼
繼前段時間我出了四個階段的Java swing的學生資訊系統後,大家反響不錯,所以緊接著就開始錄製Java web的學生系統,還是跟以前一樣,分為四個階段,每個階段都是獨立完整的系統,第一階段實現的功能是基本的學生資訊管理功能,目前第一階段、第二階段、第三階段已經錄製完成,沒
mysql合並和時間函數
eat _for 逗號 時間 then 一行 指定 time ces sql:利用group_concat()方法,參數為需要合並的字段,合並的字段分隔符默認為逗號,可通過參數separator指定,該方法往往配合group by 一起使用。利用group_concat()
MySQL的字符集和字符編碼筆記
mysql字符亂碼比較初級,深入的請參考盧sir的博客:http://cenalulu.github.io/linux/character-encoding/http://cenalulu.github.io/mysql/mysql-mojibake/GBK 和UTF8的實際在系統裏面的存放方式: 1、GBK
實用工具mycli:MySQL、MariaDB 和 Percona 的命令行界面
mysqlmycli 是默認的 MySQL 客戶端的現代替代品,mycli 將在你輸入時自動補全關鍵字、表名、列和函數。HomePage: http://mycli.net 使用效果如下:RHEL, Centos安裝方式: 目前作者沒有針對RHEL, Centos提供RPM包,暫時可用pip方式
mysql中replicate_wild_do_table和replicate_do_db區別
lan rep cati mil 多人 pan think lte 避免 使用replicate_do_db和replicate_ignore_db時有一個隱患,跨庫更新時會出錯。 如在Master(主)服務器上設置 replicate_do_db=test(my.conf
微信公眾開發URL和token填寫詳解
res wrap this true 進行 -m tmp sem 知識 微信公眾開發URL和token填寫詳解 方法/步驟 作為一名微信公眾號開發者,別人進入你的微信公眾號,肯定會看見某些網頁,或者給你發某些信息,你需要實時自動回復,所以你