高性能MySQL-筆記3-索引等等

高性能MySQL-筆記3-索引等等

關於索引使用及限制

B-Tree索引

匹配條件:(複合多列的索引)

  • 全值匹配
  • 匹配最左前綴
  • 匹配列前綴
  • 匹配範圍值
  • 精確匹配第一列並範圍匹配第二列【必須是第一第二列】

限制條件:(複合多列的索引)

  • 不按最左第一個開始查找,則無法使用索引。
  • 必須是順序條件,不能跳過中間索引列。【第二列排序是在精確匹配第一列情況下,第三列匹配是在精確匹配到第二列的情況下,生效的】
  • 範圍查詢後的所有列都無法使用索引優化。

其他索引

  • 哈希索引:Memory引擎表才支持,略過。【InnoDB有自適應哈希索引,自動的不管了】
  • 空間數據索引R-Tree,MyISAM引擎支持,略過。
  • 全文索引,特定需求下使用,另外再系統的學習。
  • 聚簇索引,這個是InnoDB表的主鍵索引。╮(╯_╰)╭
  • 覆蓋索引,對InnoDB很有用的,需要索引覆蓋到所有使用的數據,則會很大程度提升性能。【比如覆蓋主鍵id,提高全表count的性能】【栗子:P171-P174】

使用策略

  • 使用獨立的列,不對列數據進行函數或其他計算處理。
  • 對長數據做前綴索引,索引長度需要測試,限制是無法使用此索引排序與分組。
  • 非主鍵順序插入大量的數據後,使用OPTIMIZE TABLE進行一次重新組織表。
  • 利用索引進行排序的時候,需要order by 的順序與索引規則一致。

一個栗子

栗子對的是一張表 【P183】

  • 不要建立太多個索引,重複冗餘的。【一個是空間的開銷,一個是選擇優化的開銷】
  • 範圍查詢列儘量放在索引的最後列,避免索引無效。
  • 避免多個範圍查詢【書上的解決是使用邏輯繞過方案,我覺得直接保留篩選率最高的在前即可,因爲業務上的範圍查詢可能很多,無法考慮到所有的繞過方案】
  • 最後總結:都是沒用的東東,完全不切實際,因爲通常的查詢條件都呀的是動態的,有N個。╮(╯_╰)╭

一些其他信息

  • MySQL在5.0+ 引入了“索引合併”的策略,好像可以使用多個索引的樣子 。【如果看到這個,其實說明需要優化索引了,據書上說,性能不高,使用或略索引語句:optimizer_switch 或者 IGNORE INDEX


關於查詢性能優化【乾貨】

一些的建議

  • 關聯查詢禁止使用*返回所有關聯表字段。通常使用table.*

  • 大量關聯查詢可以進行拆分多個查詢進行。【比如十幾張表的關聯╮(╯_╰)╭ ,最後在子查詢可以有固定值的情況下拆分】

  • 使用show full PROCESSLIST查看數據庫線程狀態

  • 一個對in(...)大量數據查詢的優化 (╯‵□′)╯︵┻━┻ 這個在5.6的版本已經優化了 參考文章

    select * from table_a where table_a.col in (select col from table_b where ...)
    -- 以上這種寫法,的效率會很低,因爲mysql並不會先進行in內部的只查詢,而是變成exists(),這樣就是掃描table_a全表了。╮(╯_╰)╭  
    -- 這裏的優化可以有以下兩種   
    -- ****這個在5.6的版本已經優化了,已經優化爲第二種寫法了 (╯‵□′)╯︵┻━┻ *****
    -- ****  親測5.7.2的版本中是一樣的效果了 就都沒差了各種寫法*****
    
    -- 第一種這個方法據說效率更快,我還沒試過
    select * from table_a where table_a.col in (select group_concat(col) from table_b where ... )
    -- 以上這種方法無法使用,in裏面沒辦法使用group_concat,繞過的方法爲分兩次查詢,或在以下方法
    select * from table_a where find_in_set(table_a.col,(select group_concat(col) from table_b where ... ))
    
    -- 第二種方法是常用的方法了
    select * from table_a inner join table_b on table_b.col = table_a.col where ... 
    
    -- group_concat的長度限制
     show variables like 'group_concat_max_len';
     SET GLOBAL group_concat_max_len=4294967295 ;
     SET SESSION group_concat_max_len=4294967295 ;
    
  • 獲取特定條件最小id

    -- 第一個是正常的獲取最小id值,第二個爲調整後的,執行計劃是一樣的,真實使用的時候,確實會快一些的。如果有超大數據量測試的話,估計還是比較明顯的吧。
    EXPLAIN select MIN(id) FROM merchant_trade where merchant_name = '白**' 
    EXPLAIN select id FROM merchant_trade use index(primary) where  merchant_name = '王**'  limit 1
    
  • 查詢優化器提示,有很多比如:使用或忽略特定索引,是否緩存排序,等等。如沒有特殊需要不要使用,因爲我不會╮(╯_╰)╭ 【主要這裏的版本是5.5 ,現在用的都是5.6~5.7+的了,誰知道有的是不是已經優化改了 ε=(´ο`*)))唉 】【P232~P235】

  • 關聯表的索引建立在第二個表的關聯字段上。栗子:A join B using© ,則索引在B.C。

  • 在做地理位置範圍查詢的時候(經緯度),先過濾正方形最值條件,再計算具體的距離限制。

    -- 北京 經緯度(A,B)
    -- 緯度變化一度,球面南北方向距離變化:πR/180 ........111.7km
    -- 經度變化一度,球面東西方向距離變化:πR/180*cosB ....111.7*cosB
    -- B = 40、cosB = 0.766,經度變化1度,則東西方向距離變化 85.567km
    -- 以上可以作爲最值過濾條件,減少數據掃描,並在數據A,B上加上索引加快範圍查詢
    -- 想要更快的的話,可以增加AB的近似值作爲字段,而後範圍條件改爲IN()條件,完整用上了索引。
    

不一樣的說法

  • MySQL中的in查詢會進行排序之後使用二分法進行判斷,其複雜度爲O(log n),而不是等價於or的寫法O(n),所以在in()列表中有大量值的時候,處理速度並不會下降很多,反而可能很快。

  • 連接關聯的方式:join … on ,join…using , table a,table b where a=b 這三種寫法最終所有的查詢都被轉成了 Theta 風格。除了寫法不同外,沒什麼區別。【文章參考

  • MySQL沒有全連接的語法,的原因可能就是,關聯表使用的規則爲“嵌套循環關聯”,所有連接轉換爲左連接,進行循環遞歸嵌套查詢,但外層循環值爲空的情況下無法進行後續處理,所以無法完成全連接。【就是說關聯必須有一個主表,保證主表是有值的】【P215】

  • 關於COUNT:按照效率排序的話,count(字段)<count(主鍵 id)<count(1)≈count(*),所以儘量使用 count(*)

  • UNION默認情況下會去重的,等效於distinct,而通常使用UNION ALL 。畢竟去重也是有性能開銷的。

  • 在手動查詢一些數據的情況下,可以使用自定義變量進行復雜數據的查詢,還是很好用的。【P247】【雖然看着挺好用的,但是在系統中是用是做不到的,限制太多了。P244】

    -- 這裏有個用法挺不錯的 
    -- union 查詢,查詢一個值的時候,當第一個沒查到數據的時候 再查詢第二個條件
    SELECT GREATEST(@found := -1,id) FROM `app_user` where id = 666
    union all
    select id from app_user_his where @found is null and id = 666   
    

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章