- 數據類型的優化
- MySQL數據類型
- 優化策略
- 索引優化
- 索引類型
- 高性能索引策略
- 查詢優化
- 優化數據訪問
- 從好到壞的where條件應用
- 重構查詢
一、數據類型的優化
(1)MySQL數據類型
- 整數類型:
- TinyInt,存儲空間8, 字節長度1;
- SmallInt, 存儲空間16, 字節長度2;
- MediumInt,存儲空間24, 字節長度3;
- Int,存儲空間32, 字節長度4;
- BigInt,存儲空間64, 字節長度8;
- 實數類型:
- Float:字節長度8,單精度浮點數;
- Double:字節長度16,雙精度浮點數;
- Decimal:未打包的浮點數,計算中會轉化為Double;Decimal 相比於 Float 和 Double 需要額外的空間和計算開銷,因此盡量只在對小數進行精確計算時才使用,例如存儲財務數據。在數據量比較大的時候,可以考慮使用 BigInt 代替 Decimal,將需要存儲的貨幣單位根據小數的位數乘以相應的倍數即可。
- 字符串類型:
- VarChar:存儲可變長字符串,需要一個或兩個額外字節記錄字符串長度。適用於:字符串列的最大長度比平均長度大很多;列的更新很少(所以碎片不是問題);使用了UTF-8這樣復雜的字符集,每個字符都使用不同的字節數進行存儲。
- Char:定長,根據定義的字符串長度分配足夠的空間。Char 適合存儲很短的字符串,或者所有值都接近同一個長度。如:存儲密碼的MD5值(這是一個定長的值);經常變更的數據(定長的 Char 類型不容易產生碎片);非常短的列,比如用 char(1) 來存儲只有Y和N的值,如果采用單字節字符集只需要一個字節,但是 varchar(1) 卻需要兩個字節(還有一個記錄長度的額外字節)。
- 時間類型
- DATETIME:使用8字節存儲空間,將日期和時間裝到格式為YYYYMMDDHHMMSS的整數中;
- TIMESTAMP:使用4字節存儲空間,顯示的值依賴於時區。盡量使用它,因為它的空間效率更好。
(2)優化策略
- 更小的通常更好
- 更小的通常更快,因為它占用更小的磁盤、內存和cpu緩存,且處理時需要的cpu周期更小;
- 但是要確保沒有低估需要存儲的值的范圍。
- 簡單就好
- 簡單的數據類型操作需要更少的cpu處理周期;
- 如:整型比字符串代價更低、MySQL內建類型(date,time,datetime)而非字符串來存儲時間、用整型存儲IP地址。
- 盡量避免使用NULL
- 通常最好指定列為NOT NULL,除非真的需要存儲NULL值;
- 因為如果查詢中包含可為 NULL 的列,對 MySQL 來說更難優化,因為可為 NULL 的列使得索引、索引統計和值比較都更復雜;可為 NULL 的列會使用更多的存儲空間,在MySQL里也需要特殊處理;當可為 NULL 的列被索引時,每個索引記錄需要一個額外的字節。
二、索引優化
(1)索引類型
- B-Tree索引:
- 通常意味着所有值按順序存儲,並且每一個葉子葉到根的距離相等;
- 能加快訪問速度,因為存儲引擎不需要全表掃描來捕獲需要的數據,而是從索引的根節點開始進行搜索;
- 對索引順序存儲,所以很適合查找范圍數據
- B-Tree索引有效的查詢類型:
- 全值匹配:和索引中所有列進行匹配;
- 匹配最左前綴:只使用索引第n列匹配;
- 匹配列前綴:只匹配某一列值的開頭部分;
- 匹配范圍值:某一列在xx和xxx之間的值;
- 精確匹配某一列,范圍匹配另一列:某一列全匹配,另一列范圍匹配;
- 只訪問索引的查詢:只訪問索引,不訪問數據行。
- B-Tree索引的限制:
- 如果不是按照索引的最左列查找,則無法使用索引;
- 不能跳過索引中間的列;
- 如果查詢中有某個列的范圍查詢,則其右邊所有列都無法使用索引優化查找;(如果范圍查詢有限,建議使用多個等於代替范圍查詢)。
- 哈希索引:
- 基於哈希表實現,只有精確匹配索引所有列的查詢才有效;
- 對於每一行數據,存儲引擎都會對所有索引列計算一個哈希碼,哈希索引將所有哈希碼存儲在索引中,同時在哈希表中保存指向每個數據行的指針;
- 哈希索引的限制:
- 只包含哈希值和行指針,不存儲字段,所以不能使用索引中的值避免讀取行;
- 不是按索引值順序存儲,所以不能排序;
- 不支持部分索引列匹配查找;
- 訪問哈希索引的速度非常快,除非出現很多哈希沖突,出現很多哈希沖突的話,一些索引維護的代價非常大;
- 哈希索引的應用:
- InnoDB“自適應哈希索引”:某些索引值被引用的非常頻繁,他會在內存中基於B-Tree索引的基礎上創建一個哈希索引。
(2)高性能索引策略:
- 索引的優點:
- 索引可以大大減少數據庫表的掃描量
- 索引可以幫助服務器避免排序和臨時表
- 索引可以將隨機I/O變成順序I/O
-
索引選擇:
- 前綴索引:使得索引更小,更快(比如要索引很長的字符串),但是無法做GROUP BY和ORDER BY操作,也無法覆蓋掃描;
- 索引列順序:經驗法則是將選擇性最高的放在最前面;
-
聚簇索引:實際上是一種數據的存儲方式
- 數據航存放在索引的葉子結點,且數據行和相鄰的鍵值緊湊地存放在一起
- 優點:
- 可以將相關數據保存在一起,減少磁盤I/O
- 索引和數據保存在一個B-Tree,數據訪問更快
- 使用覆蓋索引的掃描時可以直接使用主鍵
- 缺點:
- 插入速度依賴於插入順序,最好是按照主鍵順序插入
- 更新列代價很高
- 插入行可能導致頁分裂
三、查詢優化
(1)優化數據訪問
- 避免查詢不需要的記錄:使用limit;
- 避免多表查詢查詢所有列:不要隨意使用select * ;
- 重復查詢相同數據:采用緩存;
(2)從好到壞的where條件應用
- 最佳:存儲引擎層在索引中使用where過濾不匹配的記錄
- 次佳:使用索引覆蓋掃描,直接從索引中過濾不需要的記錄並返回,在服務器層完成
- 最次:先從數據表中返回數據,然后過濾,需要回表查詢
(3)重構查詢
- 一個復雜查詢改為多個簡單查詢
- 切分查詢:
- 對大查詢“分而治之”,減少鎖持有的時間
- 例如刪除過期記錄,每次LIMIT 10000,否則可能一次鎖住很多數據,占滿整個事務日志,耗盡系統資源,阻塞很多小但是重要的查詢;
- 分解關聯查詢:
- 讓緩存效率更高;
- 減少鎖的競爭;
- 應用層關聯便於表的拆分,更容易做到高性能和可擴展;
- 減少冗余記錄查詢;
要解決數據量大的問題,是避不開數據庫優化的,下面就來介紹一些常見的數據庫優化策略
1,表結構優化
表結構優化是數據庫優化中最重要的,需要結合實際情況來看怎么設計更加的優化合理
2,sql語句優化
*sql語法優化,寫出更加便捷的sql語句
*處理邏輯優化,如配合索引和緩存的使用
一個常見的做法是,將涉及到大數據量的sql語句記錄下來,觀察日志,有側重點的優化
3,分庫分表
分區是指將一張表的數據按照一定的規則分到不同的區來保存。若一張表中有幾種類型,可以考慮分表
舉一個例子,分區按照月份來分,將不同類型的字段分表,這么做的好處就是增刪改查數據的時候范圍已經大大縮小了
4,索引優化
索引的原理是在進行增刪改的時候就預先按照指定的字段順序排列后保存了,在查找的時候就可以從索引找到對應的指針找到數據
優點:查詢效率很高 缺點:每次增刪改要更新索引,降低增刪改的速度
5,分離活躍數據
將活躍數據單獨存放起來
比如登錄網站,可以將活躍度高的用戶單獨存放(依據最近登錄時間或者單位時間內登錄次數等),查詢時先從活躍數據查找,沒有再去不活躍處查找
6,讀寫分離
讀寫分離的本質是對數據庫進行集群,在高並發的情況下降低單台服務器的壓力。
一般將寫的服務器叫主服務器,寫入后同步到讀服務器(即從服務器),並將讀請求分配到多個服務器上
參考文獻:《高性能MySQL》