高性能Mysql筆記 — 優化


性能優化

了解查詢的整個生命周期,清楚每個階段的時間消耗情況

性能分析

慢查詢日志——服務器性能分析

參考
慢查詢日志是優化很重要的手段,但是開啟慢查詢日志對性能的影響並不大,所以可以考慮在線上打開慢查詢日志

  • 查看慢查詢是否打開、以及日志存儲位置:show variables like '%slow%'
    統計當前數據庫連接狀態
    mysql -e 'show processlist \G' -uroot -proot | grep State | sort | uniq -c | sort -rn

剖析單條查詢

select @@profiling:查看profiling是否打開
set profiling=1:打開profiling
show profiles:查看每條查詢的性能
show profile for query id:查看query id的詳細時間花費
information_schema.profiling:該表存儲了每個query的詳細時間花費
show status:查看會話級別的計數器
show global status:查看全局的計數器
show status where variable_name like '%handler%':查看某些變量的計數

查詢性能優化

查詢由多個子任務組成,優化查詢也就是優化子任務

  1. 消除一些子任務
  2. 減少子任務執行次數
  3. 讓子任務執行更快

優化數據訪問

不要請求不需要的數據

  1. 只返回必要的行(limit)、列(盡量不要使用星號返回所有列)
  2. 盡量不要查詢重復的數據,使用緩存

是否在掃描額外的記錄

mysql衡量查詢開銷的指標:

  1. 響應時間
  2. 掃描行數
  3. 返回的行數

訪問類型
explain語句中的type指明了訪問類型,包括:全表掃描,索引掃描,范圍掃描,唯一索引查詢,常數引用,從左到右掃描的行數從多到少,速度從慢到快
查詢語句中where條件的使用,性能從好到壞是:

  1. 在索引中使用where條件過濾不匹配的記錄,這是在存儲引擎層完成的
  2. 使用覆蓋引擎(extra中出現using index)來返回記錄,直接從索引過濾不需要的記錄並返回結果,在在服務器層完成,不需要回表
  3. 在表中返回數據,使用where過濾不匹配的記錄(extra中出現using where),在服務層完成。mysql需要先讀數據然后過濾

分解復雜查詢

  1. 切分查詢:將數據量大的查詢切分為幾次(有些情況分析查詢的性能更好,比如刪除數據,每次刪除10條比一次刪除100條來得好,當在數據庫業務繁忙的時候)
  2. 分解關聯查詢:
    • 緩存效率高:mysql中如果關聯表發生了變化,緩存就失效了;而且應用程序可以緩存切分查詢之后的結果
    • 執行單個查詢減少鎖競爭
    • 數據庫表不做強關聯,在應用層做,擴展性更好

mysql執行、優化查詢的方式

mysql查詢優化器的局限性

優化器只關心隨機頁面的讀取

  1. 關聯子查詢:有時候可以使用join的方式重寫關聯子查詢,效率更好
  2. union的限制:mysql不能將條件放入union各個查詢中,重寫的時候可以把共同的條件寫入各個查詢中
  3. 索引合並優化:mysql可以利用同一張表上的多個索引,explain的時候type為index_merge,key為使用到的索引。如果存在合並(and的情況)那么可以考慮將多個單列索引合為一個多列索引
  4. 等值傳遞
  5. 並行執行:
  6. 松散索引
  7. 哈希關聯
  8. 最大值和最小值:mysql的min和max函數
  9. 在同一個表上查詢和更新:mysql不允許同時對一張表查詢和更新,可以使用join的方式來select需要在該表上查詢的字段

干涉查詢優化器

mysql提供了一些選項來干涉優化器的行為,但是建議一般情況下不要使用,因為一般干涉優化器帶來的收效較小,反而給版本升級的時候帶來一些問題

優化特定類型的查詢

count

count(col):查詢該列值得個數(不包含null)
count(星號):查詢行數

  1. myisam全表count(星號)很快
  2. 對於不精確的統計使用緩存

優化關聯查詢

  1. 確保on和using列上有索引,A join B on col,那么一般只需要在B的col創建索引就夠了
  2. 確保group by 和order by的表達式只涉及一個表中的列,mysql才可以使用索引來優化

優化子查詢

使用關聯查詢代替子查詢,在mysql5.6和mariadb不需要考慮

優化group by和order by

group by的結果默認會按照分組字段進行排序,如果不需要排序可以去掉排序,指定order by NULL

優化分頁查詢

當頁碼比較多的時候需要掃描的數據較大,這個時候可以使用覆蓋索引進行優化,先使用索引覆蓋查詢出limit的分頁數據,然后join該表,查詢其他字段,這樣就減少了掃描的行數

select * from user_order inner join (select order_id from user_order order by buy_date limit 50, 5) as lim on lim.order_id=user_order.order_id;

或者可以記下該分界行的標識列(該列最好有索引),比如主鍵id,然后查詢基於該分界的記錄

select * from user_order where order_id > 500 order by order_id limit 5;

對於總記錄數,如果不那么精確的話可以使用explain的rows

優化union查詢

除非有消除重復行的必要,否則使用union all,因為使用union會在臨時表上加distinct,導致對整個臨時表做唯一性校驗

使用自定義變量


免責聲明!

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



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