系統優化怎麼作-SQL優化

前言

數據庫很重要!很重要!很重要! 重要的事情說三遍。因此單獨用一篇來說述SQL怎麼優化。這裏提早說到一點,不建議在業務代碼裏寫不少複雜業務SQL,基本儘量的減小 join,子查詢 等,也就說盡可能在應用層來解決問題,下降產生低效SQL的機率,數據庫只是完成數據存儲及最簡單查詢的組件。前端

SQL優化

主要4個方向,如下4個方向儘量達到了,SQL的執行效率就提升了。mysql

  1. 避免全表掃描
  2. SQL中儘量不使用臨時表
  3. 減少查詢中間結果集大小
  4. 儘量命中索引

發現慢SQL

DBA開啓MySQL的慢查詢日誌,對每日數據庫慢查詢進行監控。慢查詢後每日彙總提供開發進行處理。DBA給出指導意見。sql

分析執行計劃

主要看對SQL的執行過程當中數據庫

explain [extended] select … from … where …

獲得結果是mysql優化

+—-+————-+——-+——-+————-+——-+——-+——————-+———+———+——-+-+——-+——-+—-+———-+—————+———-+———+———+——-+——+——-+
| id | select_type | table | type  | possible_keys     | key     | key_len | ref   | rows | Extra |
+—-+————-+——-+——-+————-+——-+——-+——————-+———+———+——-+-+——-+——-+—-+———-+—————+———-+———+———+——-+——+——-+

其中 table 表示是哪一個表的數據。性能

  1. type比較重要。表示連接的類型。連接類型由好到壞的,依次是 system > const > eq_ref > ref >
    fulltext > ref_or_null > index_merge > unique_subquery >
    index_subquery > range > index > ALL 通常狀況,至少要達到 range 級別,最好是 ref
    級別。不然可能會有性能問題。
  2. possible_keys 是指能夠應用到該表的索引,若是爲NULL則沒有。
  3. key 是指用到的索引。
  4. key_len 是索引的長度,在不影響查詢精度的狀況下,值越小越好。
  5. ref 是指索引的那一列被使用了。通常會是個常數。
  6. rows 是指有多少行。
  7. extra 是指額外的信息。也是比較重要的。
若是值爲 distinct ,說明mysql 找到了域行聯合匹配的行,就再也不查找了。
若是值爲 not exits : mysql優化了 left join ,一旦找到了 left join 匹配的行,便再也不進行搜索了。
若是值爲 rang checked for each : 沒有找到理想的索引。
若是爲 using filesort ,則須要改進sql了。這說明 mysql執行 須要 文件排序。這是比較影響效率的。
若是爲 using temporary , 這是使用了 臨時表。 這種狀況也比較影響效率,sql須要改進。或者從應用層進行改進。
若是爲 where used 說明使用了where語句。若是 type爲 all 或者 index ,通常會出現這樣的結果。這樣的問題,通常是查詢須要改進。

SQL優化實例

分頁查詢

第一種分頁寫法優化

select * 
  from t
 where thread_id = 771025
   and deleted = 0
 order by gmt_create asc limit 0, 15;

原理:日誌

一次性根據過濾條件取出全部字段進行排序返回。code

數據訪問開銷=索引IO + 索引所有記錄結果對應的表數據IO

缺點:排序

該種寫法越翻到後面執行效率越差,時間越長,尤爲表數據量很大的時候。適用場景:當中間結果集很小(10000行如下)或者查詢條件複雜(指涉及多個不一樣查詢字段或者多表鏈接)時適用。

第二種分頁寫法:

select t.* from (
     select id from t
     where 
     thread_id = 771025 
     and deleted = 0 order by gmt_create asc limit 0, 15) a, t 
 where a.id = t.id;

前提:

假設t表主鍵是id列,且有覆蓋索引secondary key:(thread_id, deleted, gmt_create)

原理:

先根據過濾條件利用覆蓋索引取出主鍵id進行排序,再進行join操做取出其餘字段。

數據訪問開銷=索引IO+索引分頁後結果對應的表數據IO

優勢:

每次翻頁消耗的資源和時間都基本相同,就像翻第一頁同樣

適用場景:

當查詢和排序字段(即where子句和order by子句涉及的字段)有對應覆蓋索引時,且中間結果集很大的狀況時適用

批量SQL

減小和數據庫交互次數
INSERT ... ON DUPLICATE KEY UPDATE
 REPLACE INTO
 INSERT IGNORE
 INSERT INTO VALUES()
  • 對同一個表的屢次alter操做必須合併爲一次操做。
  • mysql對錶的修改絕大部分操做都須要鎖表並重建表,而鎖表則會對線上業務形成影響。爲減小這種影響,必須把對錶的屢次alter操做合併爲一次操做。例如,要給表t增長一個字段b,同時給已有的字段aa創建索引,
    一般的作法分爲兩步:
alter table t add column b varchar(10);

而後增長索引:

alter table t add index idx_aa(aa);

正確的作法是:

alter table t add column b varchar(10),add index idx_aa(aa);

總結

數據庫是有狀態的服務,變動複雜並且速度慢,若是把業務邏輯放到數據庫中,將會限制業務的快速發展。建議把業務邏輯提早,放到前端或中間邏輯層,而把數據庫做爲存儲層,實現邏輯與存儲的分離。

思考題

  1. 萬一通過SQL優化後,仍是達不到要求,還有什麼手段能進行優化呢?
  2. 在一個既有系統前期業務快速迭代,致使系統不少業務已經寫了不少低效的SQL,致使系統運行緩慢,領導須要快速解決運行緩慢的問題,有哪些手段能夠用呢?
相關文章
相關標籤/搜索