1.選擇InnoDB引擎
理由:
(1)支持事務(wù)
InnoDB與傳統(tǒng)的ISAM與MyISAM相比,InnoDB的最大特色就是支持了ACID兼容的事務(wù)(Transaction)功能,類似于PostgreSQL。
(2)支持行鎖
MyISAM只支持表級鎖,用戶在操作myisam表時,select,update,delete,insert語句都會給表自動加鎖,如果加鎖以后的表滿足insert并發(fā)的情況下,可以在表的尾部插入新的數(shù)據(jù)。
InnoDB的行鎖,只是在WHERE的主鍵是有效的,非主鍵的WHERE都會鎖全表的。
2.選擇自增ID作為主鍵
在使用InnoDB存儲引擎時,如果沒有特別的需要,請永遠使用一個與業(yè)務(wù)無關(guān)的自增字段作為主鍵。
InnoDB使用聚簇索引,數(shù)據(jù)記錄本身被存于主索引(一顆B+Tree)的葉子節(jié)點上。這就要求同一個葉子節(jié)點內(nèi)(大小為一個內(nèi)存頁或磁盤頁)的各條數(shù)據(jù)記錄按主鍵順序存放,因此每當有一條新的記錄插入時,MySQL會根據(jù)其主鍵將其插入適當?shù)墓?jié)點和位置,如果頁面達到裝載因子(InnoDB默認為15/16),則開辟一個新的頁(節(jié)點)。如果表使用自增主鍵,那么每次插入新的記錄,記錄就會順序添加到當前索引節(jié)點的后續(xù)位置,當一頁寫滿,就會自動開辟一個新的頁。這樣就會形成一個緊湊的索引結(jié)構(gòu),近似順序填滿。由于每次插入時也不需要移動已有數(shù)據(jù),因此效率很高,也不會增加很多開銷在維護索引上。
如果使用非自增主鍵(如果身份證號或?qū)W號等),由于每次插入主鍵的值近似于隨機,因此每次新紀錄都要被插到現(xiàn)有索引頁得中間某個位置,此時MySQL不得不為了將新記錄插到合適位置而移動數(shù)據(jù),甚至目標頁面可能已經(jīng)被回寫到磁盤上而從緩存中清掉,此時又要從磁盤上讀回來,這增加了很多開銷,同時頻繁的移動、分頁操作造成了大量的碎片,得到了不夠緊湊的索引結(jié)構(gòu),后續(xù)不得不通過OPTIMIZE TABLE來重建表并優(yōu)化填充頁面。
InnoDB的輔助索引data域存儲相應(yīng)記錄主鍵的值而不是地址。換句話說,InnoDB的所有輔助索引都引用主鍵作為data域。因此不建議使用過長的字段作為主鍵,因為所有輔助索引都引用主索引,過長的主索引會令輔助索引變得過大。
3.單表字段總的Size不宜過大
主鍵(即聚簇索引)的B+樹上葉子節(jié)點與數(shù)據(jù)存放在一起。每一個節(jié)點在數(shù)據(jù)庫中都是一個頁,頁是innodb磁盤管理最小的單位,innodb每個頁的大小是16K。單行數(shù)據(jù)越小,每個頁存儲的行數(shù)就越多。
如何計算當前表的理論上分表的最大值
在開始這一塊之前,我們需要了解以下幾個信息:
① 每一個節(jié)點在數(shù)據(jù)庫中都是一個頁,頁是innodb磁盤管理最小的單位,innodb每個頁的大小是16K,且不可更改。常見的類型有:數(shù)據(jù)頁 B-tree Node;undo頁 Undo Log Page;系統(tǒng)頁 System Page;事務(wù)數(shù)據(jù)頁 Transaction system Page;插入緩沖位圖頁 Insert Buffer Bitmap;插入緩沖空閑列表頁 Insert Buffer freeBitmap;未壓縮的二進制大對象頁Uncompressed BLOB Page;壓縮的二進制大對象頁 Compressed BLOB Page。
② 每個key后有個頁號4B,還有6B的其他數(shù)據(jù)(參考《MySQL技術(shù)內(nèi)幕:InnoDB存儲引擎》P193的頁面數(shù)據(jù))
③ 裝載因子(InnoDB默認為15/16)
以下是針對單行數(shù)據(jù)在300bit大小的數(shù)據(jù)計算步驟:
?①索引節(jié)點:(16000/(8+4+6))15/16=833.33個
?②葉子節(jié)點:假設(shè)單行數(shù)據(jù)300b,計算為(16000/(300+8+4+6))15/16=47.17
?③總共三層B+樹可存儲數(shù)據(jù)量為:833.33833.3347.17=32756682條數(shù)據(jù)
根據(jù)以上計算步驟,300b數(shù)據(jù)量情況下理論單表三度索引數(shù)據(jù)大概是3275w數(shù)據(jù)
3.聯(lián)合索引的最左匹配原則
與b+樹檢索是比較key相關(guān)
4.union、in、or 都能夠命中索引,建議使用 in
or:新版的 MySQL 能夠命中索引
5.負向條件查詢不能使用索引,可以優(yōu)化為 in 查詢
負向條件有:!=、<>、not in、not exists、not like 等。
6.把計算放到業(yè)務(wù)層而不是數(shù)據(jù)庫層
7.強制類型轉(zhuǎn)換會全表掃描
where語句中字段與匹配值類型不同時會觸發(fā)強制類型轉(zhuǎn)換。
8.更新十分頻繁、數(shù)據(jù)區(qū)分度不高的字段上不宜建立索引
更新索引字段值會變更 B+ 樹,更新頻繁的字段建立索引會大大降低數(shù)據(jù)庫性能。
“性別”這種區(qū)分度不大的屬性,建立索引是沒有什么意義的,不能有效過濾數(shù)據(jù),性能與全表掃描類似。
一般區(qū)分度在80%以上的時候就可以建立索引,區(qū)分度可以使用 count(distinct(列名))/count(*) 來計算。
9.如果有 order by、group by 的場景,請注意利用索引的有序性
order by 最后的字段是組合索引的一部分,并且放在索引組合順序的最后,避免出現(xiàn) file_sort 的情況,影響查詢性能。
例如對于語句 where a=? and b=? order by c,可以建立聯(lián)合索引(a,b,c)。
如果索引中有范圍查找,那么索引有序性無法利用,如 WHERE a>10 ORDER BY b;,索引(a,b)無法排序。