首頁  >  文章  >  資料庫  >  詳細介紹MySQL查詢最佳化

詳細介紹MySQL查詢最佳化

迷茫
迷茫原創
2017-03-26 11:46:071054瀏覽

1、簡介

     一個好的web應用,最重要的一點是有著優秀的存取效能。資料庫MySQL是web應用的組成部分,也是決定其效能的重要部分。所以提升MySQL的效能至關重要。

     MySQL效能的提升可分為三個部分,包括硬體、網路、軟體。其中硬體、網路取決於公司的財力,需要白嘩啦的銀兩,這裡就不說啦。軟體又細分為很多種,在這裡我們透過MySQL的查詢優化來達到效能的提升。

     最近看了一些關於查詢優化的書籍,同時也在網路上閱讀一些前輩們寫的文章。

以下是自己整理借鏡查詢最佳化的一些總結:

2、截取SQL語句

     1、全面查詢日誌

     2、慢查詢日誌

     3、二進位日誌

     4、進程清單

  SHOW FULL PROCESSLIST;

#  。 。 。

3、查詢最佳化基本分析指令

  1、EXPLAIN {PARTITIONS|EXTENDED}

  2、SHOW CREATE TABLE tab;

  3、SHOW INDCREATE TABLE tab;

  3、SHOW IND CREATESEXSEXSEXS FROM tab;

  4、SHOW TABLE STATUS LIKE 'tab';

  5、SHOW [GLOBAL|SESSION] STATUS LIKE '';

  6、SHOW VARIABLES>

#  。 。 。 。

  ps:我自己都覺得上面都是沒任何營養的東西。下面才是真正的乾貨哈。

4、查詢最佳化幾個方向

  1、盡量避免全文掃描,給對應欄位增加索引,應用索引來查詢

  2、刪除不用或重複的索引

  3、查詢重寫,等價轉換(謂詞、子查詢、連接查詢)

  4、刪除內容重複不必要的語句,精簡語句

  5、整合重複執行的語句

  6、快取查詢結果

5、索引最佳化

  5.1、索引優點:

#    1、維持資料的完整性

    2、提高資料的查詢效能

    3、改進表的連接操作(jion)

    4、對查詢結果進行排序。沒索引將會採用內部文件排序演算法進行排序,效率較慢

    5、簡化聚合資料操作

  5.2、索引缺點

    1、索引需要佔用一定的缺點

    1、索引需要佔用一定的缺點儲存空間

    2、資料插入、更新、刪除時會受索引的影響,效能會降低。因為資料變更索引也需要更新

    3、多個索引,優化器需要耗時則優選擇

  5.3、索引選擇

    1、資料量大時採用

    2、資料高度重複時,不採用

    3、查詢取出資料大於20%,將採用全文掃描,不用索引

  5.4、細密索引

#    資料查詢:

    MySQL中的InnoDB、MyISAM都是B-Tree類型索引

    B-Tree包含:PRIMARY K

##    B-Tree

    B-Tree型索引不支援(即欄位使用下列符號時,將不採用索引):

    >, <, >=, <=, BETWEEN, !=, <, <, >=, <=, BETWEEN, !=, <, <, >=, <=, BETWEEN, !=, <, <, >=, <=, BETWEEN, !=, <, <, >=, <=, BETWEEN, !=, <, <, >=, <=, BETWEEN, !=, <, <, >=, <=, BETWEEN, !=, <, <, >=, <=, BETWEEN, !=, <, < >,like '%**'

    【在此先介紹一下覆蓋索引】

    以我自己理解的方式介紹吧。覆蓋索引並不是像主鍵索引、唯一索引一樣真實存在,它只是對索引應用某些特定場景的一種定義【另一種理解:查詢的列是索引列,因此列被索引覆蓋】。它可以突破傳統的限制,使用以上操作符,並且仍然採用索引進行查詢。

    因為查詢的列是索引列,所以不需要讀取行,只需要讀取列字段資料就可以了。 【例如你看一本書,需要找某一內容,剛好那內容出現在目錄中,那就不用一頁頁翻了,直接在目錄中定位到第幾頁查找】

    如何激活覆蓋索引呢?什麼樣才是特定場景呢?

    索引字段,在select中出現就是了。

    複合索引還可能有其他的特殊場景。例如,三列複合索引,只需要在select、where、group by、order by中,任一個地方出現一次複合索引最左邊列就可以啟動使用覆蓋索引了。

    查看:

    EXPLAIN中Extra顯示有Using index表示這條語句採用了覆蓋索引。

    結論:

#    不建議在查詢的時候使用select*from進行查詢了,應該寫需要用的字段,並且增加相應的索引,以提高查詢性能。

    針對以上操作符實測結果:

    1、以select*from形式,where中是primary key可以通殺【除like】(使用主鍵進行查詢);index則全不全不可以。

###    2、以select 欄位a from tab where 欄位a《以上運算子》形式測試,結果仍可使用索引查詢。 【採用了覆蓋索引】###

    其他索引最佳化方法:

    1、使用索引關鍵字作為連接的條件

    2、複合索引作為連接的條件

    2、複合索引作為連接的條件

    2、複合索引使用

     2、到的欄位合併成複合索引

    4、where、和group by涉及欄位加索引

6、子查詢最佳化

  在from中為非相關子查詢,可以上拉子查詢到父層。在多表連接查詢考慮連線代價再選擇。

  查詢最佳化器對子查詢一般採用巢狀執行的方式,也就是對父查詢中的每一行,都執行一次子查詢,這樣子查詢會執行很多次。這種執行方式效率很低。

  子查詢轉換為連接查詢優點:

  1、子查詢不用執行很多次

  2、優化器可以根據資訊來選擇不同的方法和連接順序

  3、子查詢的連結條件,篩選條件變成父查詢的篩選條件,以提高效率。

  最佳化:

  子查詢合併,若多個子查詢,能合併的盡量合併。

  子查詢展開,即上拉變成多表查詢(時刻保證等價變化)

  注意:

  子查詢展開只能展開簡單的查詢,若子查詢含有聚集函數、GROUP BY、DISTINCT,則不能上拉。

  select * from t1 (select*from tab where id>10) as t2 where t1.age>10 and t2.age<25;

#  select*from t1,tab as t2 where

##  select*from t1,tab as t2 where t1.age>10 and t2.age<25 and t2.id>10;

  具體步驟:

  1、from與from合併,修改對應參數

#  22 、where與where合併,用and連接

  3、修改對應的謂詞(in改=)

7、等價謂詞重寫:

  1、BETWEEEN AND改寫為>= 、<=之類的。實測:十萬條數據,重寫前後時間,1.45s、0.06s

#  2、in轉換多個or。欄位為索引時,兩個都能用到索引,or效率相對in好一點

  3、name like 'abc%'改寫成name>='abc' and name<'abd';

  注意:百萬級資料測試,name沒有索引之前like比後一種查詢快;給字段增加索引後,後面的快一點點,相差不大,因為兩種方法在查詢的時候都用到了索引。

  。 。 。 。

8、條件化簡與最佳化

  1、將where、having(不存在groupby和聚集函數時)、join-on條件能合併的盡量合併

2.刪除不必要的括號,減少語法分許的or和and樹層,減少cpu消耗

  3、常數傳遞。 a=b and b=2轉換為 a=2 and b=2。盡量不使用變數a=b或a=@var

  4、消除沒用的SQL條件

  5、where等號右邊盡量不出現表達式計算;where中不要對字段進行表達式計算、函數的使用

  6、恆等變換、不等式變換。範例:測試百萬級資料a>b and b>10變成a>b and a>10 and b>10優化顯著

9、外連接最佳化

#  即將外連接轉為內連接

  優點:

  1、優化處理器處理外連接比內連接步驟多且耗時

  2、外連接消除後,優化器選擇多表連接順序有更多選擇,可以擇優而選

  3、可以將篩選條件最為嚴格的表作為外表(連接順序最前面,是多層循環體的外循環層),

  可以減少不必要的I/O開銷,能加快演算法執行的速度。

  on a.id=b.id與where a.id=b.id的差別,on則表進行連接,where則進行資料對比

  注意:前提必須是結果為NULL決絕(即條件限制不要NULL資料行,語意上是內連接)

  最佳化原則:

  精簡查詢,連接消除,等效轉換,去除多餘表物件連接

#  例如:主鍵/唯一鍵作為連接條件,且中間表列只作為等值條件,可以去掉中間表連接

10、其他查詢優化

  1、以下將會造成放棄索引查詢,採用全文掃描

    1.1、where 子句中使用!=或<>運算子注意:主鍵支援。非主鍵不支援

    1.2、避免使用or

      經測試,並非是使用了or就一定不能使用索引,大多情況下是沒用到索引,但還有少數情況是用到的,因此具體情況具體分析。

      類似優化:

      select * from tab name='aa' or name='bb';

                   select * from tab name='aa'

      union all

      select * from tab name='bb';

#                         實      無實         3  3   3  都  」       〴 、十萬數據測試,在沒任何索引的情況下,上面比下面的查詢速率快一倍。

      2、三十萬資料測試,aa與bb都是單獨索引情況下,下面的查詢速率比or快一點。

    1.3、避免使用not in

      not in一般不能使用索引;主鍵字段可以

    .4、where中可以盡量避免使用對#null#nf. like不能前置百分號like '%.com'

      解決:

        1、若必須使用前置%,且資料長度     1、若必須使用前置%,且資料長度,例如URL,可將資料翻轉入資料庫,再來查。 LIKE REVERSE'%.com';

        2、使用覆蓋索引

    1.6、使用索引欄位作為條件的時候,假欄位是複合索引,   1.6、使用索引欄位作為條件的時候,假欄位是複合索引,則應該使用索引名稱最縮寫1.6、左邊的欄位作為條件

  2、將exists代替in

    select num from a where num in(select num from b)

   se select num from a where

##    se =a.num)

    一百萬條數據,篩選59417條數據用時6.65s、4.18s。沒做其他優化,僅只是將exists替換in。

  3、欄位定義是字串,查詢時沒帶引號,不會用索引,會進行全文掃描。

  【以下是摘抄於半夜亂彈琴博文http://www.cnblogs.com/lingiu/p/3414134.html,本人沒進行相應的測試】

  4、盡量使用表變數來取代臨時表

  5、避免頻繁建立和刪除臨時表,以減少系統表資源的消耗

  6、如果使用到了臨時表,在儲存過程的最後務必將所有的臨時表明確刪除,先truncate table ,然後drop table ,這樣可以避免系統表的較長時間鎖定

  7、盡量避免使用遊標,因為遊標的效率較差,如果遊標操作的資料超過1萬行,那麼就應該考慮改寫

  8、大資料量,若資料量過大,應該考慮對應需求是否合理。

  9、盡量避免大事務操作,提升系統並發能力。

以上是詳細介紹MySQL查詢最佳化的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn