我在項目中對 MySQL 作的優化

原標題:我在 MySQL 上作了哪些優化
原文連接:zhoupq.com/我在-MySQL-上作…
轉載請註明出處mysql

  本文記錄了我這一年的時間裏是如何對項目中用到的 MySQL 進行優化。帶有必定的主觀性和侷限性,請各位支持的同時,不吝賜教。
算法

  

安裝


  這是同事分享給個人。安裝數據庫也是一門學問,千萬不要被安裝的簡單性而忽略一些細節。針對於 Win os 服務器而言,MySQL 的安裝版能夠選則三種不一樣的服務器類型:

  • Developer Machine(開發機器)
      爲 MySQL 分配最少分系統資源
  • Server Machine(服務器)
      爲 MySQL 分配必定比例的系統資源
  • Dedicated MySQL Server Machine(專用MySQL服務器)
      爲 MySQL 分配全部的系統資源

  若是你跟我同樣不幸,不只選擇了 Win os 作服務器系統,還選擇了 Developer Machine(開發機器),兄弟抱一個,不要哭,重裝。發生這些上述不幸的緣由已經不重要,須要作的是必須切換成 Dedicated MySQL Server Machine(專用MySQL服務器)sql

  重裝切換以後,你會發現,以前安裝的必定是假的 MySQL。數據庫

主鍵


  主鍵或者惟一鍵能夠用做某條記錄的惟一標誌符。主鍵生成有兩種方式:
+ 自增
+ UUID

自增


  自增方式有個重要因素是「步長」,也就是則增的幅度,在單機模式下,通常步長爲1。如果在分佈式數據庫系統下,步長設爲節點的數量,這樣一來,就能夠避免主鍵重複的狀況。建議預估好節點的數量,步長不可小於節點數。

UUID


  UUID 能夠更有效地避免自增主鍵帶來的煩惱,可是它也有不足之處:
+ UUID 過長,增大數據庫總容量,下降性能
+ UUID 無序,插入數據時根據主鍵尋址費時

  針對上述 UUID 的缺點,推特開發了「雪花算法」,並開源。其中心思想是利用時間戳、數據中心碼、機器碼、序列號組成有規則的 UUID,使其有序下降性能消耗。

  我在項目中使用了「自增+步長2」,由於使用了主從,雖然不是分佈式,可是雙數據源也是兩個節點,採用這種方式保險一些。

  更多內容請移步個人其餘博文: 數據庫自增加主鍵與-UUID
  推薦 MySQL 使用自增ID主鍵和UUID 做爲主鍵的優劣比較詳細過程(從百萬到千萬表記錄測試)

數據類型

長度


  我一直秉承殺雞就用殺雞刀,宰牛採用宰牛刀的原則。一個「tab_NAME」 的數據類型非要整一個 「VARCHAR(500)」,這是浪費,過多的長度分配會形成空間佔用太多,最終形成性能降低。有同事說我杞人憂天,一個庫才二十幾張表,即便每一個字段都設成500,也不過如此嘛。從短時間的結果上來看,結果沒有受到明顯影響。可是別忘了,咱們是來解決問題的,若是由於咱們的操做違反了約定,形成嚴重後果,那麼咱們將揹負罪過。「量身定作」的好處不言而喻,列的長度亦是如此。

NULL


  儘可能不將列設爲 NULL,從業務角度上看,NULL 是錯誤的,試想,既然是 NULL,哪有何須存在這個列呢?反之,既然存在這個列,那麼 NULL 便失去了意義。讓我設計表的時候,我都會給列設置一個初始值,「tab_UPDATETIME」 就設置爲 「CURRENT_TIMESTAMP」,「tab_STATUS」 就設置爲 「1」或者「0」。

  從開發維護的角度看,若是不肯定列是否爲 NULL,那麼在 SQL 中,就必須加上 「AND tab_NAME != NULL AND tab_NAME != ''」,很容易被忽略,代碼越多,出錯的機率就越大。緩存

索引


  好的索引是一顆仙丹,可讓遲緩的查詢獲得質的提高,不然,就是一碗毒藥。

  索引我作了三點優化:bash

  • 勿濫用索引
  • 最左前綴索引
  • 前綴索引

勿濫用索引


  索引不是越多越好,由於生成索引須要時間,並且索引佔表物理空間。表一大,查詢速度多少會受影響。我親眼看到同事建好表時候,無微不至地爲每個字段都建了索引,或者爲每個條件都建了索引,形如條件「a=1 and b =2 and c=3 and d=4」,爲其建了「a」、「b」、「c」、「d」四個索引。浪費!低效!這種狀況,應當使用「最左前綴索引」。

最左前綴索引


  在生成聯合索引時會碰到最左前綴索引,什麼是最左前綴索引呢?就是在聯合索引中,從最左邊的索引開始匹配,直到趕上「like」、「>」、「>=」、「<」、「<=」等範圍匹配時中止,即便後面有「=」都再也不匹配。

  簡單舉例:現有字段「a」、「b」、「c」、「d」組成的聯合索引「abcd」,SQL 條件部分爲:服務器

  1. a=1 and b =2 and c=3 and d=4
  2. a=1 and b =2 and d=4 and c=3
  3. a=1 and b =2 and c>=3 and d=4

  1 用到索引爲「abcd」,2 用到的索引爲「abd」, (2 同 1)3 用到的索引爲「abc」。條件的順序很重要。跟自拍同樣,臉大的站後面。
  
  抱歉,上述第二點同第一點,一樣用到的索引爲「abcd」。
  
  利用 EXPLAIN 工具分析:app

// 建表語句略,已知建立了組合索引 (abcd) 
mysql> EXPLAIN SELECT * FROM test t WHERE t.a = 'q' AND t.b = 'w' AND t.c = 'e' AND t.d = 'f';
+----+-------------+-------+------+---------------+------+---------+-------------------------+------+--------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref                     | rows | Extra                    |
+----+-------------+-------+------+---------------+------+---------+-------------------------+------+--------------------------+
|  1 | SIMPLE      | t     | ref  | name          | name | 360     | const,const,const,const |    1 | Using where; Using index |
+----+-------------+-------+------+---------------+------+---------+-------------------------+------+--------------------------+
1 row in set

mysql> EXPLAIN SELECT * FROM test t WHERE t.a = 'q' AND t.b = 'w' AND t.d = 'f' AND t.c = 'e';
+----+-------------+-------+------+---------------+------+---------+-------------------------+------+--------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref                     | rows | Extra                    |
+----+-------------+-------+------+---------------+------+---------+-------------------------+------+--------------------------+
|  1 | SIMPLE      | t     | ref  | name          | name | 360     | const,const,const,const |    1 | Using where; Using index |
+----+-------------+-------+------+---------------+------+---------+-------------------------+------+--------------------------+
1 row in set複製代碼

前綴索引


  前綴索引是針對某個字段而言,咱們知道 MySQL 中,有一個全文索引,「BOLD」、「TEXT」 是不能建全文索引。想一想也能理解,這麼長的全文索引得佔多少空間,這顯然是不現實的。最好的辦法是爲其建立「左前綴索引」,只取字符串的前面一小段做爲索引,具體取多少,決定於多長的字符能夠儘量多的肯定惟一記錄。「varchar」一樣受用。

  更多內容請移步個人其餘博文:MySQL 高性能索引以前綴索引框架

多表聯合查詢


  不論是 Heibernate 在代碼中拼 SQL,仍是 MyBatis 在 Mapper.xml 中寫 SQL,因爲數據庫範式的規範,致使爲完成某項查詢,必須聯合多表查詢。一個 LEFT JOIN 很常見,三四個 LEFT JOIN 呢?

  多個 LEFT JOIN 確定不行,即便有索引,也很容易形成全表掃描,爲了減小該狀況發生的機率,我通常會採起兩種方法:分佈式

  • 反範式
  • 臨時表

反範式

衡量一個 DBA 的水平有多高,得看他反範式能力有多強。
—— 知乎

  好比我要根據 A表 的日期,關聯 B表,統計出每一個日期下某個屬性的數量。我能夠在A表中添加一列,用來存儲「數量」,雖然違反了範式,可是性能上獲得了提高。我以爲這是一筆劃算的買賣。

  規範化是爲了技術服務,而技術是爲業務服務。規範化也就是套路,能保證不出錯,可是並不能解決特殊問題,特殊問題還須要特殊處理。

臨時表


  當須要聯合三張表以上時,輕微的反範式已經不適用了,推薦用臨時表,或者物化視圖,可是 MySQL 的物化視圖實現起來比較困難。事實上,我用的就是臨時表,將四張表的部分數據抽離出來,保存在一張臨時表中,制定一個「計劃」,天天凌晨會自動更新。

  • 好處
      加快查詢速度
  • 缺點
    • 會在某一時刻(凌晨)數據庫IO太高
    • 可能會出現異常,作好事務管理,讓其回滾,從新執行,再有問題,就須要人工干預
    • 數據準確性會延遲一天,適合非敏感業務

  以上是僅針對數據庫作的優化,至於緩存(一級緩存、二級緩存),那屬於持久層框架的職責,不在此文記錄範圍以內。

相關文章
相關標籤/搜索