MySQL調優


調優的目的?讓吞吐量更大,響應速度更快

關於數據庫優化,我們從以下5個維度進行。

一.優化表結構

表結構盡量遵循三范式的原則,在進行多表查詢的時候,必要時可以采用反范式化進行優化。

什么叫范式?

  • 在關系型數據庫中,關於數據表設計的基本原則,規則就稱為范式。

一共有6大范式,知道前5個就行。滿足了高級范式,就一定滿足低級范式。比如滿足第三范式,就一定滿足第1,2范式。

  • 第一范式:確保每一個字段保證"原子性",不能被拆分。比如有一個字段叫"個人信息",它就可以拆分為地址,年齡,姓名等。就不滿足第一范式
  • 第二范式:確保表中的每一條記錄,都有唯一的標識(主鍵)。所有的非主鍵字段,必須完全依賴主鍵。不能部分依賴。
    注意:這里的主鍵是聯合主鍵。比如下圖:姓名,年齡依賴球員編號;比賽時間,比賽場地依賴比賽編號;只有得分全部依賴

  • 第三范式:確保非主鍵之間是相互獨立的,不能產生依賴。下圖就不滿足

  • 巴斯范式(BCNF):3NF的增強版,在3NF的基礎上消除了主屬性對候選鍵的部分依賴或者傳遞依賴的關系。相當於主鍵中也產生了依賴關系,就不滿足巴斯范式。比如下圖

  • 第四范式:一個表中只有一對1:多的關系。如果一個表中有多個1:多的關系就不滿足第四范式。

  •  第五范式:也叫完美范式,了解有這么個東西就行

范式的優缺點?

  • 優點:消除數據冗余
  • 缺點:降低查詢效率,因為范式越高,設計出來的數據表就越多,就需要很多的關聯查詢。

反范式化?

  • 是一種空間換時間的優化手段。因為我們遵循業務優先原則,可以通過在表中增加冗余字段來提高數據庫的讀性能。
  • 當冗余信息有價值或者能大幅度提高查詢效率的時候,我們才會采用反范式化進行優化。

 

數據庫的設計原則?三少一多

  • 數據表的個數越少越好
  • 數據表中的字段個數越少越好
  • 數據表中聯合主鍵的字段個數越少越好
  • 使用主鍵和外鍵越多越好。這里是指外鍵關系越多,就可以重復的利用數據,而不是指在表中建立好多外鍵。

數據庫表建模的工具?

  • PowerDesigner
二.優化邏輯查詢

關聯查詢優化:最好"被驅動表加索引"

  • 外連接:一般驅動表是全表查詢(就算添加索引也是index),被驅動表是索引查詢。(也就是說最好給被驅動表添加索引,驅動表加不加都行)
    • 如:student是驅動表,book是被驅動表   :EXPLAIN SELECT * FROM student LEFT JOIN book ON student.card = book.card;
  • 內連接:誰是驅動表誰是被驅動表由優化器決定,優化器滿足"小表驅動大表"。(2個都加索引,讓優化器自己決定;如果只加 一個索引,優化器肯定選擇加索引的作為被驅動表)

優化器中join 的原理?

  • 不加索引
    • Simple Nested-Loop Join(簡單嵌套循環連接) 

    • Block Nested-Loop Join(塊嵌套循環連接):不再逐條獲取驅動表的數據,而是一塊一塊的獲取,引入join buffer緩存區

  

    • Hash Join:MySQL8.0之后默認使用hash join。可以做大數據集連接。
  • 加索引
    • Index Nested-Loop Join(索引嵌套循環連接)

 

 子查詢優化:

  • 子查詢執行效率不高,使用關聯查詢(join)代替子查詢
  • 效率不高的原因:
    • 查詢的過程中需要建立一個臨時表,查詢完畢,再撤銷臨時表。消耗性能
    • 臨時表都不會使用索引

 排序優化:

  • 前提知識:MySQL支持2中排序方式,所以優化也是從這倆方面考慮
    • index排序:b+樹的葉子節點就是按照排序進行的,使用索引直接就可以保證有序性
    • FileSort排序:將需要排序的數據加載到內存中,然后進行排序。
  • 盡量使用索引完成order by排序。如果where 和order by 后面的列相同就用單索引,不同就用聯合索引。
  • 對FileSort進行調優
    • 前提知識:FileSort有2種算法
      • 雙路排序(慢):進行倆次磁盤掃描,第一次只加載需要排序的列到sort_buffer,進行排序。然后根據排序好的列,第二次從磁盤讀取其他的列。
      • 單路排序(快):一次性將所有列的數據加載到sort_buffer中,進行排序。
    • 提高sort_buffer_size:不管哪種算法,提高這個內存值肯定加大效率。
    • 提高max_length_for_sort_data:這個參數就是一個界限,需要返回的列總長度大於這個值就使用雙路,小於這個值就使用單路。

group by優化:

  • group by 優化的方法和order by一樣。

分頁查詢優化:

  • 如果像下圖查詢的情況極端,盡量的使用表中其他字段的索引。

 

其他的優化

  • exists和in:小表驅動大表

  • count(*)和count(1)和count(具體字段)的效率
    • count(*)和count(1)沒有本質區別,執行時間基本一樣
    • count(具體字段)的時候,盡量使用占用空間少的二級索引。因為二級索引存儲的信息相比聚簇索引要少很多。count(*)和count(1) 系統會自動選擇占用空間少的二級索引進行統計。  
    • innodb的count()是O(n)級別的,MyISAM是O(1)級別的。
  • 關於select *
    • 盡量使用什么字段就指出來,不要使用select *。因為會加載很多沒用的列。
    • 無法使用覆蓋索引
  • 關於Limit 1:
    • 如果是全表掃描,加上Limit 1。找到數據就不會再繼續查找了,加快查找效率
    • 如果是唯一索引,找到數據也不會繼續查找了,Limit 1 就不管用了。

 

  三.優化物理查詢(索引)
  • 選擇適合做索引的字段(MySQL索引講)
  • 哪些情況導致索引失效(MySQL索引講)
  • 使用覆蓋索引:一個索引包含了滿足查詢結果的數據就叫做覆蓋索引。(也就是需要的列恰好都在索引的葉子節點上存儲,不需要回表)
    • 好處:無需回表;可以把隨機IO變成順序IO加快查詢效率(利用到索引都是順序IO,因為索引就是有順序的)。
  • 使用索引下推:如圖

    • 索引下推就用在一些and查詢語句中,本來通過非聚集索引zipcode查詢出來數據,要進行回表,但是如果查出來100條,分別對這100條進行回表就很浪費性能,icp就是先不進行回表,使用后面的條件進行過濾,過濾完畢之后比如剩下10條,對這10條進行回表就行了。
    • set optimizer_switch = 'index_condition_pushdown=on'     //開啟索引下推
  • 使用隱藏索引:之前索引要是刪除后,發現效果不好或者出錯,只能重新添加索引。一刪一加浪費性能,現在就可以先隱藏索引,讓索引不起作用。發現效果不錯,再刪除索引。
    • create index 索引名 on 表名(列名) invisible
四.使用緩存

對於熱點數據可以使用redis或者Memcached作為緩存,減少數據庫的壓力

五.庫級優化

從以下3個方面進行調優。

1.優化MySQL服務器:在my.cnf或者my.ini文件的[mysqld]組中配置。

  • innodb_buffer_pool_size:表示表和索引的最大緩存。這個值越大,查詢速度越快。
  • key_buffer_size:表示索引緩存區的大小,索引緩存區是所有線程共享,對於4GB左右的服務器該參數可設置為256M或384M。
  • table_cache:表示同時打開的表的個數。默認為2402,調到512-1024最佳,這個值不是越大越好,因為同時打開好多表影響操作系統的性能。
  • query_cache_size:表示查詢緩存區的大小。這個就是MySQL架構中的查詢緩沖器。在8.0廢除,需要配合query_cache_type才能使用。
  • query_cache_type:0代表關閉,1代表開啟,2代表自定義。
    • 關於自定義:eg:select SQL_CACHE * from test where id=5  使用SQL_CACHE可以自定義的在sql聲明使用查詢緩存
  • sort_buffer_size:表示每一個需要進行排序的線程分配的緩存區的大小。提高這個參數的值可以提高order by和group by的速度。對於4GB左右的服務器建議設置為6-8M。如果有100個連接,實際分配的總共排序緩存區的大小為6 * 100 = 600MB。
  • join_buffer_size = 8M:表示聯合查詢操作時所能使用的緩存區大小,每一線程獨享。
  • read_buffer_size:表示每個線程連續掃描時為掃描的每一個表分配的緩沖區的大小。默認為64K,可設置為4M。
  • innodb_flush_log_at_trx_commit:表示何時將緩存區的數據寫入日志文件
    • 0:表示每秒1次,將數據寫入日志文件並將日志文件寫入磁盤。
    • 1:表示每次提交事務,將數據寫入日志文件並將日志文件寫入磁盤。
    • 2:表示每次提交事務,將數據寫入日志文件,每隔1s將日志文件寫入磁盤。
  • innodb_log_buffer_size:事務日志所使用的緩存區,log buffer的值。
  • max_connections:表示允許連接到MySQL數據庫的最大數量
  • back_log:用於控制MySQL監聽TCP端口時設置的擠壓請求棧大小,比如:max_connections為500,其他來的請求就可以放入這個棧中。5.0之前為50,現在一般為50+(max_connections / 5)。
  • thread_cache_size:線程緩沖池的大小
  • wait_timeout:一個請求的最大連接時間,4GB的服務器一般設置為5-10。
  • interactive_timeout:表示服務器在關閉連接前等待行動的秒數。

 2.優化數據庫結構:

  • 拆分表:冷熱數據分離,將一些查詢頻率高的列放在一個表中,查詢頻率不高的列放在另一個表中。
  • 添加中間表:對於聯合查詢,使用一個中間表記錄它們之間的關系,將原來的聯合查詢改為對中間表的查詢,加快效率。
  • 優化數據類型:優先選擇符合存儲需要的最小的數據類型。
    • 存儲整數一般使用int型,非負型數據(自增id,整型ip)可以使用unsigned型,因為無符號相對於有符號,同樣的字節數,存儲量更大(不用給負數留空間)。
    • 避免使用TEXT,BLOB類型。
    • 使用TimeStamp存儲時間
    • 使用Declmal代替float和double存儲精准浮點數,因為Declmal為精准浮點型,在計算時不會丟失精度,占用空間由定義的寬度決定。
  • 使用分析表,檢查表,優化表的語句
    • 分析表:分析關鍵字的分布,analyze table ...
    • 檢查表:檢查表中是否存在錯誤,check table ...
    • 優化表:消除刪除/更新造成的空間浪費,optimize table...,只能優化varchar,blob,text類型的字段,整理文件的碎片,重新規划空間。
  • 創建全局通用表空間:create tablespace...,相對於獨享表空間,可以節約元數據方面的內存。

3.大表優化:

  • Memcached(高速緩存系統)+ MySQL(垂直拆分:拆分表結構) (拆分表)
  • mysql主從復制,讀寫分離
  • 分表分庫 + 水平拆分 + Mysql 集群 (水平拆分:把數據庫中的每個表中的數據,拆分在不同的數據庫中)(拆分表中的數據)
    • 分庫:不同的模塊擁有自己的不同的數據庫
    • 分表:水平拆分,垂直拆分
    • 出現的問題:分布式id;分布式事務;排序,分頁的問題(二次排序,先在自己數據庫排序,后結合在一起進行排序)
    • 參考資料:分庫分表你要怎么分?

 

今天是除夕,祝大家新年快樂!

 寄語:放棄可以找到一萬個理由,堅持只需要一個信念! 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM