mysql查詢優化小技巧

1. 開啓緩存
mysql> show variables like 'query_cache%';
mysql> set global query_cache_type=1;
mysql> set global query_cache_size=1024*1024*32

注意:mysql

  1. 查詢緩存存在判斷是嚴格依據select語句自己的:嚴格保證sql一致。
  2. 若是查詢時包含動態數據,則不能被緩存。
  3. 若是不想使用緩存,可使用 SQL_NO_CACHE 語法提示。
2. in型子查詢
select goods_id,cat_id,goods_name from good where cat_id in(select cat_id form category where parent_id=6);
這條語句執行會很是慢,由於它會掃描goods全表,逐行與category表對照
緣由:mysql的查詢優化器,針對in型作了優化,優化成了exists的執行效果。
改進:用鏈接查詢代替子查詢
select goods_id,g.cat_id,g.goods_name from goods as g inner join (select cat_id from category where parent_id=6) as t;
3. from 子查詢

內層 from 語句查到的臨時表,沒有索引,因此from返回的內容要儘可能少算法

4. count()優化

沒有查詢條件時count(*)很是快,不須要查表。但當有查詢條件時,速度將減慢。
可使用縮小範圍的方法優化查詢。
eg.sql

須要統計good_id>100的總數時通常會寫爲:
select count(*) form goods where good_id>100;
優化爲:
slect (select count(*) from goods)-(select count(*) from goods where id<100);
這樣,就把範圍由無限大縮小到了100
5. group by 優化
  • 分組用於統計,而不用於篩選數據。
  • 用索引避免產生臨時表和文件排序
  • A,B錶鏈接查詢,group by和order by 的列儘可能相同,並且列應該爲A的列

默認狀況下,MySQL 對全部 group by col1, col2, …… 的字段進行排序。這與查詢中指定 order by col1,col2,…… 相似。所以,若是顯示包括一個包含相同列的 order by 子句,則對 MySQL 的實際執行性能沒有什麼影響。 數據庫

若是查詢包括 group by 但用戶想要避免排序結果的消耗,則能夠指定 order by null 禁止排序。緩存

select col1 from table group by col2 order by null;
6. union 優化

union all 不過濾 效率提升,如非必須,請用union all
由於 union去重的代價很是高, 放在程序裏去重.服務器

7. limit & 分頁優化

limit offset,n 當offset很是大時,效率極低。mysql並非跳過offset行,而後單取n行,而是取offset+n行,返回放棄前offset行,返回n行。
優化:性能

  1. 從業務上解決
    不容許翻過100頁(百度也是如此)
  2. 利用索引
  3. id,name from goods inner join (select id from goods limit 5000000,10) as tmp using(id);
  4. 記錄上一次取出的最後一條數據,把 limit m, n 語句轉化爲 limit n。

8. 消除msyql內部臨時表

在一些sql請求中,mysql會建立臨時表,可能建立到內存中,也可能由內存中轉存到磁盤。
會建立臨時表的查詢:優化

  1. group by 的列沒有索引,必建立臨時表
  2. order by 與 group by 爲不一樣列時,或多表聯查時order by,group by 包含的列不是第一張表的列,必產生臨時表。
  3. distinct 與 order by 一塊兒使用可能會產生臨時表
  4. union合併查詢時會用到臨時表

9. 大批量插入數據

對於 myisam 引擎

若是是空的 myisam 表,默認就是先導入數據才建立索引的,不存在優化問題。
對於非空的 myisam 表,在一次性插入大量數據時,能夠經過設置 disable keys 和 enable keys 來提升導入的效率。線程

# 假設給 test 表一次性插入大量數據  
alert table test disable keys;

loading the data ……

alert table test enable keys;
對於 innodb 引擎

disable keys 的方式適用於 myisam 引擎,但不適用於 innodb 引擎。指針

  1. 由於 innodb 類型的表是按照主鍵的順序保存的,因此將導入的數據按照主鍵的順序排列,能夠有效的提升導入數據的效率。
  2. 在導入數據前執行 set unique_checks=0 , 關閉惟一性校驗,在導入結束後執行 set unique_checks=1,恢復惟一性校驗,能夠提升導入的效率。
  3. 若是應用使用自動提交的方式,建議在導入前執行 set autocommit=0,關閉自動提交,導入結束後再執行 set autocommit=1,打開自動提交,也能夠提升導入的效率。

10. 優化 insert 語句

同一客戶端一次插入多行

使用多個值表的 insert 語句,能夠減小客戶端與數據庫之間的鏈接、關閉等資源消耗

insert into test values (1,1),(2,2),(3,3)……
從不一樣客戶插入不少行,可使用 insert delayed 語句獲得更高的素的。

delayed 的含義是讓 insert 語句立刻執行,其實數據都被放在內存的隊列中,並無真正的寫入磁盤,這比每條土局分別插入要快的多;
low_priority 恰好相反,在全部其餘用戶對錶的讀寫完成後才進行插入(好比記錄日誌的場景)

將索引文件和數據文件分在不一樣的磁盤上存放(利用建表中的選項)
若是進行批量插入,能夠經過增長 bulk_insert_buffer_size 變量值的方法來提升速度,可是,這隻能對 myisam 表使用。
當從一個文本文件裝載一個表時,使用 load data infile 。這一般比使用不少 insert 語句快 20 倍。

11. 優化 order by 語句

mysql 的兩種排序方式
  1. 經過有序索引順序掃描直接返回有序數據,這種方式在使用 explain 分析查詢時顯示爲 using index ,不須要額外的排序,操做效率極高。
  2. 經過對返回的數據行進行排序,也就是一般說的 filesort 排序,全部不是經過索引直接返回排序結果的排序都叫作 filesort 排序。filefort 並不表明經過磁盤文件進行排序,而只是說明進行了一個排序操做,至於排序操做是否使用了磁盤文件或臨時表等,則取決於 MySQL 服務器對排序參數的設置和須要排序數據的大小。
  • filesort 是經過相應的排序算法,將取得的數據在 sort_buffer_size 系統變量設置的內存排序區中進行排序,若是內存裝載不下,它就會將磁盤上的數據進行分塊,再對各個數據塊進行排序,而後將各個塊合併成有序的結果集。sort_buffer_size 設置的排序區是每一個線程獨佔的,因此同一個時刻,mysql 中存在多個sort buffer 排序區。
優化思路

儘可能減小額外的排序,經過索引直接返回有序數據。
where 條件和 order_by 使用相同的索引,而且 order_by 的順序和索引的順序相同,而且 order by 的字段都是升序或者降序。不然確定須要額外的排序操做,這樣就會出現 filesort 。

filesort 的優化

在某些不得不使用 filesort 的場景中,須要想辦法加快 filesort 的操做。對於 filesort ,MySQL 有兩種排序算法。

  • 兩次掃描算法:

首先根據條件取出排序字段和行指針信息,以後在排序區 sort_buffer 中排序。若是排序區 sort buffer 不夠,則在臨時表 temporary table 彙總存儲排序結果,完成排序後根據行指針回表讀取記錄。這種算法須要兩次訪問數據,第一次獲取排序字段和行指針信息,第二次根據行指針獲取記錄,尤爲是第二次讀取操做可能致使大量隨機 I/O 操做;優勢是排序的時候內存開銷較少

  • 一次掃描算法:

一次性取出知足條件的行的全部字段,而後在排序區 sort buffer 中排序後直接輸出結果集,排序的時候內存開銷較大,可是排序效率比兩次掃描算法要高。

mysql 經過比較系統變量 max_length_for_sort_data 的大小和 query 語句取出的字段總大小來判斷使用哪一種排序算法。若是 max_length_for_sort_data 更大,那麼使用第二種優化以後的算法,不然使用第一種算法。
適當加大系統變量 max_length_for_sort_data 的值,可以讓 MySQL 選擇更優化的 filesort 的排序算法,固然,設置過大,會形成cpu利用率太低和磁盤 I/O 太高

適當加大 sort_buffer_size 排序區,儘可能讓排序在內存中完成,而不是經過建立臨時表放在文件中進行;固然也不能不限制加大 sort_buffer_size 排序區,由於 sort_buffer_size 參數時每一個線程獨佔的,因此要考慮數據庫活動鏈接數和服務器內存的大小來適當設置排序區。

儘可能只使用必要的字段,select 具體的字段名稱,而不是 select * 選擇全部字段,這樣能夠減小排序區使用,提升 sql 性能。

12. 使用 sql 提示

sql 提示(sql hint) 是優化數據庫的一個重要手段,簡單來講就是在 sql 語句中加入一些人爲的提示來達到優化操做的目的。

select sql_buffer_results * from ……

這個語句將強制 MySQL 生成一個臨時結果集。只要臨時結果集生成後,全部表上的鎖定均被釋放。
這能再遇到表鎖定問題時或要花很長時間將結果傳給客戶端時有所幫助,由於能夠儘快釋放鎖資源。

經常使用的 sql 提示:

  • use index 提供但願 MySQL 去參考的索引列表,就可讓 MySQL 再也不考慮其餘可用的索引。
  • ignore index 忽略一個或者多個索引
  • force index 強制 MySQL 使用一個特定的索引。
相關文章
相關標籤/搜索