mysql索引分析

====================================================== 
 鏈接
 mysql -h 192.168.100.176 -u VISITSTAT -pZFiwjg2Nrr
 
 數據庫
 use visit_stat;
 
 建立索引
 alter table entry_page_attraction_analyze add index index_attraction(data_date);
 alter table entry_page_conversion_analyze add index index_conversion(data_date);
 alter table entry_page_flow_analyze add index index_flow(data_date);
 alter table entry_page_kpi_summary add index index_kpi(data_date);
 alter table entry_page_visitor_analyze add index index_visitor(data_date);
======================================================




索引場景分析:
    某個表有(C1,C2,C3,C4),如下只能使用聯合索引的C1,C2,C3部分
    A.where C1=x and C2=x and C4>x and C3=x
    B.where C1=x and C2=x and C4=x order by C3
    C.where C1=x and C4=x group by C3,C2
    D.where C1=? and C5=? order by C3,C2
    E.where C1=? and C2=? and C5=? order by C2,C3
    
    A.where C1=x and C2=x and C4>x and C3>x
    Mysql內部會優化sql語句,優化結果:where C1=x and C2=x and C3=x and C4>x ,因此都能用上
    
    B.where C1=x and C2=x and C4=x order by C3  C1能,C2能,C3能,  C4用不上
    
    D.where C1=? and C5=? order by C3,C2    C1能,C2能,C3能
    
解決思路B-Tree索引的左前綴匹配原則
    Myisam,Innodb默認使用B-Tree索引
    B-Tree索引:排好序的能夠快速查找的數據結構[排好序,可快速查找,能夠範圍查找]
    Hash索引:在memory表裏,默認是hash索引,時間複雜度是o(1)
    [hash值隨機,在磁盤上放置也是隨機,沒法快速定位,沒法範圍優化]
    
單個索引意義不大.開發中大部分的時候使用的是多列索引號

多列索引號要想利用上必須知足最左前綴原則
分析index(A,B,C)
where A=3   A能
where A=3 and B=5    A能,B能
where A=3 and B=5 and C=4    A能,B能,C能
where B=3 or C=4    沒有使用索引[違反了最左前綴原則]
where A=3 or C=4    A能,B不能,C不能[中間斷層了]
where A=3 and B>10 and C=4    A能,B能,C不能[B是範圍,沒法定位C]
where A=3 and B like 'foo%' and C=10    A能,B能,C不能,[同上]




實戰:
mysql> explain select name,age from person where  name LIKE '%pttxs%' and age >= 49\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: person
         type: index
possible_keys: NULL
          key: name_age
      key_len: 128
          ref: NULL
         rows: 4114293
        Extra: Using where; Using index
1 row in set (0.00 sec)

ERROR:
No query specified

mysql> explain select name,age from person where  name LIKE 'pttxs%' and age >= 49\G;
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: person
         type: range
possible_keys: name_age
          key: name_age
      key_len: 128
          ref: NULL
         rows: 1016160
        Extra: Using where; Using index
1 row in set (0.00 sec)

其一.這裏分析了兩句select查詢,差異在於1.row是name LIKE '%pttxs%'    2.row name LIKE 'pttxs%',
顯然1.row第一個沒有用到索引,從possible_keys: NULL能夠看出
其二.從rows能夠看出1. row>>>>rows: 4114293    2.row>>>rows: 1016160可見1. row形成全表掃描了


分析2.
mysql> explain select name,age from person where  name LIKE 'pttxs%' and age >= 49 order by phone \G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: person
         type: ALL
possible_keys: name_age
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 4114293
        Extra: Using where; Using filesort
1 row in set (0.00 sec)

ERROR:
No query specified
注意:這裏phone沒有創建索引,沒有排好序, Using filesort說明在文件或者內存中進行了2次排序,並且沒有利用索引

 

建索引的幾大原則

1.最左前綴匹配原則,很是重要的原則,mysql會一直向右匹配直到遇到範圍查詢(>、<、between、like)就中止匹配,好比a = 1 and b = 2 and c > 3 and d = 4 若是創建(a,b,c,d)順序的索引,d是用不到索引的,若是創建(a,b,d,c)的索引則均可以用到,a,b,d的順序能夠任意調整。
2.=和in能夠亂序,好比a = 1 and b = 2 and c = 3 創建(a,b,c)索引能夠任意順序,mysql的查詢優化器會幫你優化成索引能夠識別的形式
3.儘可能選擇區分度高的列做爲索引,區分度的公式是count(distinct col)/count(*),表示字段不重複的比例,比例越大咱們掃描的記錄數越少,惟一鍵的區分度是1,而一些狀態、性別字段可能在大數據面前區分度就是0,那可能有人會問,這個比例有什麼經驗值嗎?使用場景不一樣,這個值也很難肯定,通常須要join的字段咱們都要求是0.1以上,即平均1條掃描10條記錄
4.索引列不能參與計算,保持列「乾淨」,好比from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,緣由很簡單,b+樹中存的都是數據表中的字段值,但進行檢索時,須要把全部元素都應用函數才能比較,顯然成本太大。因此語句應該寫成create_time = unix_timestamp(’2014-05-29’);
5.儘可能的擴展索引,不要新建索引。好比表中已經有a的索引,如今要加(a,b)的索引,那麼只須要修改原來的索引便可mysql

 

列子:sql

select
   count(*) 
from
   task 
where
   status=2 
   and operator_id=20839 
   and operate_time>1371169729 
   and operate_time<1371174603 
   and type=2;數據庫

根據最左匹配原則,最開始的sql語句的索引應該是status、operator_id、type、operate_time的聯合索引;
其中status、operator_id、type的順序能夠顛倒,因此我纔會說,把這個表的全部相關查詢都找到,會綜合分析;數據結構

好比還有以下查詢
select * from task where status = 0 and type = 12 limit 10;
select count(*) from task where status = 0 ;
那麼索引創建成(status,type,operator_id,operate_time)就是很是正確的,由於能夠覆蓋到全部狀況。這個就是利用了索引的最左匹配的原則函數

相關文章
相關標籤/搜索