MySQL查詢優化

一、簡介

     一個好的web應用,最重要的一點是有着優秀的訪問性能。數據庫MySQL是web應用的組成部分,也是決定其性能的重要部分。因此提高MySQL的性能相當重要。php

     MySQL性能的提高可分爲三部分,包括硬件、網絡、軟件。其中硬件、網絡取決於公司的財力,須要白嘩嘩的銀兩,這裏就不說啦。軟件又細分爲不少種,在這裏咱們經過MySQL的查詢優化從而達到性能的提高。html

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

如下是本身整理借鑑關於查詢優化的一些總結:算法

二、截取SQL語句

     一、全面查詢日誌數據庫

     二、慢查詢日誌緩存

     三、二進制日誌網絡

     四、進程列表併發

  SHOW FULL PROCESSLIST;函數

  。。。性能

三、查詢優化基本分析命令

  一、EXPLAIN {PARTITIONS|EXTENDED}

  二、SHOW CREATE TABLE tab;

  三、SHOW INDEXS FROM tab;

  四、SHOW TABLE STATUS LIKE ‘tab’;

  五、SHOW [GLOBAL|SESSION] STATUS LIKE ‘’;

  六、SHOW VARIABLES

  。。。。

  ps:我本身都感受上面都是沒任何養分的東西。下面纔是真正的乾貨哈。

四、查詢優化幾個方向

  一、儘可能避免全文掃描,給相應字段增長索引,應用索引來查詢

  二、刪除不用或者重複的索引

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

  四、刪除內容重複沒必要要的語句,精簡語句

  五、整合重複執行的語句

  六、緩存查詢結果

五、索引優化

  5.一、索引優勢:

    一、保持數據的完整性

    二、提升數據的查詢性能

    三、改進表的鏈接操做(jion)

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

    五、簡化聚合數據操做

  5.二、索引缺點

    一、索引須要佔用必定的存儲空間

    二、數據插入、更新、刪除時會受索引的影響,性能會下降。由於數據變動索引也須要進行更新

    三、多個索引,優化器須要耗時則優選擇

  5.三、索引選擇

    一、數據量大時採用

    二、數據高度重複時,不採用

    三、查詢取出數據大於20%,將採用全文掃描,不用索引

  5.四、索引細究

    資料查詢:

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

    B-Tree包含:PRIMARY KEY, UNIQUE, INDEX, and FULLTEXT

    B-Tree類型索引不支持(即字段使用如下符號時,將不採用索引):

    >, <, >=, <=, BETWEEN, !=, <>,like ‘%**’

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

    以我本身理解的方式介紹吧。覆蓋索引並非像主鍵索引、惟一索引同樣真實存在,它只是對索引應用某些特定場景的一種定義【另外一種理解:查詢的列是索引列,所以列被索引覆蓋】。它能夠突破傳統的限制,使用以上操做符,且依然採用索引進行查詢。

    由於查詢的列是索引列,因此不須要讀取行,只須要讀取列字段數據就能夠了。【例如你看一本書,須要找某一內容,恰好那內容出如今目錄中,那就不用一頁頁翻了,直接在目錄中定位到第幾頁查找】

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

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

    複合索引還可能有其餘的特殊場景。例如,三列複合索引,僅須要在select、where、group by、order by中,任意一個地方出現一次複合索引最左邊列就能夠激活使用覆蓋索引了。

    查看:

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

    結論:

    不建議在查詢的時候使用select*from進行查詢了,應該寫須要用的字段,而且增長相應的索引,以提升查詢性能。

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

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

    二、以select 字段a from tab where 字段a《以上操做符》形式測試,結果依然可使用索引查詢。【採用了覆蓋索引】

    其餘索引優化方法:

    一、使用索引關鍵字做爲鏈接的條件

    二、複合索引使用

    三、索引合併or and,將涉及到的字段合併成複合索引

    四、where、和group by涉及字段加索引

六、子查詢優化

  在from中爲非相關子查詢,能夠上拉子查詢到父層。在多表鏈接查詢考慮鏈接代價再選擇。

  查詢優化器對子查詢通常採用嵌套執行的方式,即對父查詢中的每一行,都執行一次子查詢,這樣子查詢會執行不少次。這種執行方式效率很低。

  子查詢轉化爲鏈接查詢優勢:

  一、子查詢不用執行不少次

  二、優化器能夠根據信息來選擇不一樣的方法和鏈接順序

  三、子查詢的鏈接條件,過濾條件變成父查詢的篩選條件,以提升效率。

  優化:

  子查詢合併,若多個子查詢,能合併的儘可能合併。

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

  注意:

  子查詢展開只能展開簡單的查詢,若子查詢含有彙集函數、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 t1.age>10 and t2.age<25 and t2.id>10;

  具體步驟:

  一、from與from合併,修改相應參數

  二、where與where合併,用and鏈接

  三、修改相應的謂詞(in改=)

七、等價謂詞重寫:

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

  二、in轉換多個or。字段爲索引時,兩個都能用到索引,or效率相對in好一點

  三、name like ‘abc%’改寫成name>=’abc’ and name<’abd’;

  注意:百萬級數據測試,name沒有索引以前like比後一種查詢快;給字段增長索引後,後面的快一點點,相差不大,由於兩種方法在查詢的時候都用到了索引。

  。。。。

八、條件化簡與優化

  一、將where、having(不存在groupby和彙集函數時)、join-on條件能合併的儘可能合併

  二、刪除沒必要要的括號,減小語法分許的or和and樹層,減小cpu消耗

  三、常量傳遞。a=b and b=2轉換爲 a=2 and b=2。儘可能不使用變量a=b或a=@var

  四、消除沒用的SQL條件

  五、where等號右邊儘可能不出現表達式計算;where中不要對字段進行表達式計算、函數的使用

  六、恆等變換、不等式變換。例:測試百萬級數據a>b and b>10變爲a>b and a>10 and b>10優化顯著

九、外鏈接優化

  即將外鏈接轉爲內鏈接

  優勢:

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

  二、外鏈接消除後,優化器選擇多表鏈接順序有更多選擇,能夠擇優而選

  三、能夠將篩選條件最爲嚴格的表做爲外表(鏈接順序最前面,是多層循環體的外循環層),

  能夠減小沒必要要的I/O開銷,能加快算法執行的速度。

  on a.id=b.id與where a.id=b.id的差異,on則表進行鏈接,where則進行數據對比

  注意:前提必須是結果爲NULL決絕(即條件限制不要NULL數據行,語意上是內鏈接)

  優化原則:

  精簡查詢,鏈接消除,等效轉換,去除多餘表對象鏈接

  例如:主鍵/惟一鍵做爲鏈接條件,且中間表列只做爲等值條件,能夠去掉中間錶鏈接

十、其餘查詢優化

  一、如下將會形成放棄索引查詢,採用全文掃描

    1.一、where 子句中使用!=或<>操做符  注意:主鍵支持。非主鍵不支持

    1.二、避免使用or

      經測試,並不是是使用了or就必定不能使用索引,大多狀況下是沒用到索引,但還有少數狀況是用到的,所以具體狀況具體分析。

      相似優化:

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

      =>

      select * from tab name=’aa’

      union all

      select * from tab name=’bb’;

      實測:

      一、十萬數據測試,沒任何索引的狀況下,上面比下面的查詢速率快一倍。

      二、三十萬數據測試,aa與bb都是單獨索引狀況下,下面的查詢速率比or快一點。

    1.三、避免使用not in

      not in通常不能使用索引;主鍵字段能夠

    1.四、where中儘可能避免使用對null的判斷

    1.五、like不能前置百分號 like ‘%.com’

      解決:

        一、若必須使用%前置,且數據長度不大,例如URL,可將數據翻轉存入數據庫,再來查。LIKE REVERSE‘%.com’;

        二、使用覆蓋索引

 

    1.六、使用索引字段做爲條件的時候,倘若是複合索引,則應該使用索引最左邊前綴的字段名

  二、將exists代替in

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

    select num from a where exists(select 1 from b where num=a.num)

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

  三、字段定義是字符串,查詢時沒帶引號,不會用索引,將會進行全文掃描。

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

  四、儘可能使用表變量來代替臨時表

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

  六、若是使用到了臨時表,在存儲過程的最後務必將全部的臨時表顯式刪除,先 truncate table ,而後 drop table ,這樣能夠避免系統表的較長時間鎖定

  七、儘可能避免使用遊標,由於遊標的效率較差,若是遊標操做的數據超過1萬行,那麼就應該考慮改寫

  八、大數據量,若數據量過大,應該考慮相應需求是否合理。

  九、儘可能避免大事務操做,提升系統併發能力。

  。。。。。

十一、博文總結

  通過這些天查資料敲代碼的學習,瞭解到了MySQL的查詢優化並非簡簡單單的按照某個公式某個規則就可達到的。實驗是檢驗標準的惟一標準,通過這幾天的測試,得出的結論就是:MySQL的查詢優化是有大方向,可是想要得出一個萬能優化公式那是不可能的,畢竟每一條SQL查詢語句的寫法、結果着重點、以及表的字段環境都不同。可以達到看SQL查詢語句就能得出優化方法的大神,一定是仔細研究過SQL查詢優化而且有過好幾年優化經驗的老鳥。哈哈,我還只是個小菜鳥。

  建議各位正在學習SQL查詢優化的童鞋們:不要僅僅只是看,要多敲代碼,多測試,各類字段環境測試、各類數據量級別測試。

 

以上是本身的一些總結,也許有些不足。畢竟本身還只是個菜鳥,而且也不是DBA的方向,若你們發現有不足的地方,或者錯誤的地方,請您可以提出來。

 

做者:那一葉隨風

聲明:轉載時請在文章頁面明顯位置給出原文連接。

相關文章
相關標籤/搜索