MySQL索引總結

 索引前端

    相似於書目,用於快速檢索
mysql

    優勢:
sql

        提升數據檢索效率;
數據庫

        提升表間的join效率;
緩存

        利用惟一性索引,保證數據的一致性;
數據結構

        提升排序和分組效率;
併發

    缺點:
數據庫設計

         消耗更多的物理存儲;
ide

         數據變動時,索引也須要更新,下降更新效率函數

 

二叉樹、B數、B+數、hash索引

二叉樹

根節點即樹的中間節點

二叉樹的每一個節點至多隻有兩顆子樹,二叉樹的子樹有左右有序之分,次序不能顛倒

 

不適合作數據庫索引:

    一、當數據量大的時候,樹的高度會比較高,查詢會比較慢;

    二、每一個節點只存儲一個記錄,可能致使一次查詢有不少次磁盤io;

B樹

一個結點能夠擁有多於2個子節點的多叉查找樹
適合大量數據的讀寫操做,廣泛運用在數據庫和文件系統
B樹的數據不會所有出如今葉子節點
一顆m階(好比m=4)的B樹知足下列條件
    一、樹中每一個節點至多有m個(m=4)子節點;
    二、除根節點和葉子節點外,其餘每一個節點至少有m/2(2個)的子節點;
    三、若是根節點不是子節點,則至少有兩個子節點;
    四、全部葉子節點都出如今同一層,葉子節點不包含任何建值
B+樹

B+樹是B樹的變體, 還是多叉搜索樹,在B樹的基礎上,作了一些改進:

     一、非葉子節點再也不存儲數據,數據只存儲在同一層的葉子節點上;

     二、葉子之間,增長了鏈表,獲取全部節點,再也不須要中序遍歷;

     三、非葉子節點,不存儲實際記錄,而只存儲記錄的KEY的話,那麼在相同內存的狀況下,B+樹可以存儲更多索引;  

     四、在MySQL中,爲了方便,直接寫成BTREE

    

哈希索引:

    創建在哈希表的基礎上,它只對使用了索引中的每一個值的精確查找有用

    對於每一行,存儲引擎計算出了被索引的哈希碼,他是一個較小的值,而且有可能和其餘行的哈希碼相同

    把哈希碼保存在索引中,而且保證了一個指向哈希表中的每一行的指針

    MySQL中只有ndb這些存儲引擎才用哈希索引
    哈希索引的話,若是數據量過大的話會出現哈希衝突
    innodb不支持hash索引(支持自適應hash索引)

B+樹索引和哈希索引的比較

    大量惟一值的等值查詢,哈希索引效率一般比B+tree高

    hash索引不支持模糊查找

    hash索引不支持聯合索引中的最左匹配原則

    hash索引不支持排序

    hash索引不支持範圍查詢

    hash索引只能顯示應用於memory、NDB表  

 

索引使用建議

    一、常常檢索的列; 

    二、常常用於錶鏈接的列;

    三、常常排序、分組的列;

 

索引不使用建議

    一、基數很低的列;

    二、更新頻繁但檢索不頻繁的列;

    三、BLOB、TEXT等長內容列;

    四、不多用於檢索的列;

 

數據庫設計索引的緣由

    一、用於提高數據庫的查找速度

    二、提升聚合函數效率

    三、提升排序效率,order by  asc、desc

    四、有時能夠避免回表

    五、減小多表關聯時掃描行數

    六、列定義爲default null 時,null值也會有索引,存放在索引數的最前端部分,所以儘可能不要定義容許null

 

  
innodb索引類型

    彙集索引

    innodb表,只可以有一個,由於數據行在物理磁盤上只能有一份彙集存儲。        

    innodb中,表即彙集索引,彙集索引即表

    mysiam沒有彙集索引的概念

         彙集索引優先選擇的列:

            一、int/bigint

            二、數據連續(單調)遞增或自增

        不建議的彙集索引:

            一、修改頻繁的列;

            二、新增數據太過離散隨機

           無論innodb有沒有主鍵,它都會有彙集索引,由於innodb是基於彙集索引的索引組織表

           主鍵必定是彙集索引,彙集索引不必定是主鍵

    主鍵索引

         innodb的主鍵索引與行記錄是存儲在一塊兒的,故叫作彙集索引

            由於這個特性,innodb的表必需要有彙集索引:

            (1)若是表定義了PK,則PK就是彙集索引;
            (2)若是表沒有定義PK,則第一個非空unique列是彙集索引;
            (3)不然,InnoDB會建立一個隱藏的row-id做爲彙集索引;
        主鍵由表中的一個或多個字段組成,它的值用於惟一的標識表中的某一條記錄

        create table row_id(a int not null,b int null,c int not null,d int not null,unique key(b),unique key(d),unique key(c));

         insert into row_id select 1,2,3,4;

         insert into row_id select 5,6,7,8

        insert into row_id select 9,10,11,12;

        select a,b,c,d,_rowid from row_id;

        另外_rowid只能查看單列爲主鍵的狀況,對於多列組成的主鍵就顯得無能爲力了

        做用:

            一、保證數據的完整性;

            二、加快數據的操做速度;

            三、主鍵值不能重複,也不能包含null;

        主鍵選擇建議:

            對業務無心義,沒必要受限於業務變化的影響;

            不多修改和刪除;通常都是自增的

            不建議使用較長的列作主鍵,例如char(64),由於全部的普通索引都會存儲主鍵,會致使普通索引過於龐大;

            建議使用趨勢遞增的key作主鍵,因爲數據行與索引一體,這樣不至於插入記錄時,有大量索引分裂,行記錄移動;

            例如:select * from t where name='lisi';

            會先經過name輔助索引定位到B+樹的葉子節點獲得id=5,再經過彙集索引定位到行記錄。因此,其實掃了2遍索引樹。

 innodb主鍵特色:

            定義索引時,無論有無顯示包含主鍵,實際都會存儲主鍵值;

            在MySQL5.6.9版本後,優化器已能自動識別索引末尾的主鍵值,以前版本則須要顯示加上主鍵列才能夠被識別(通過測試,老版本也支持此特徵)

               例如:

仍然遵循最左前綴原則:

惟一索引

        不容許具備索引值相同的行,從而禁止重複的索引或鍵值(在惟一約束上,和主鍵同樣)

        惟一索引容許有空值(NULL);

        一個表只能有一個主鍵,但能夠有多個惟一索引;

        innodb表中主鍵必須是惟一索引,但惟一索引不必定是主鍵;

    聯合索引

        多列組成的索引

        適合where條件中的多列組合

        能夠避免回表(覆蓋索引)

        支持多列不一樣的排序規則(8.0開始支持倒序索引)

        聯合索引建議:

            where條件中,常常同時出現的列放在聯合索引中;

            把選擇性大的列放在聯合索引最左邊

        覆蓋索引

        經過索引數據結構便可完成查詢返回數據,不須要回表

        執行計劃中,Extra爲關鍵字 using index;

          desc select name from t1 where name like '%zyq%';

 

    前綴索引

        使用的緣由:

            char、varcahr列太長,所有建立索引的話,效率太差,存在浪費;

            或者blob、text類型不能整列做爲索引列,所以須要使用前綴索引

        部分索引選擇建議:

            一、統計平均值;

二、知足10%-30%的覆蓋度就能夠

        缺點:

              沒法利用前綴索引完成排序    

與所有索引對比:

全文索引
        5.6以前,全文索引支持mysiam引擎,5.6之後也支持innodb引擎
 
索引長度
索引的最大長度767bytes
啓用innodb_lagrge_prefix,增長到3072bytes,只針對dynamic,compressed格式管用
對於redundant、compact格式,最大索引長度仍是767bytes
mysiam表索引最大長度是1000bytes
最大排序長度默認是1024(max_sort_length)
 
索引管理
    建立刪除索引
        alter table  t  add index idx(c1) using btree;
        create index idx_name on t(c1) using btree;
        create table 表時也能夠順便建立索引;
        alter  table t drop index idx_name;
        drop index idx_name on t;
    MySQL各版本,對於add Index的處理方式是不一樣的,主要有三種:
Copy Table方式
這是InnoDB最先支持的建立索引的方式。建立索引是經過臨時表拷貝的方式實現的。
1. 新建一個帶有新索引的臨時表。
2. 而後鎖原表,禁止DML操做,容許讀操做。
3. 將原表數據所有拷貝到臨時表(無排序,一行行拷貝)。
4. 而後Rename,升級字典鎖,禁止讀寫。
5. 完成建立索引的操做。
這種copy方式的效率沒有inplace好 ,由於copy須要記錄undo和redo log,並且由於臨時佔用buffer pool引發短期內性能受影響。
Inplace方式
這是原生MySQL 5.5,以及innodb_plugin中提供的建立索引的方式。所謂Inplace,也就是索引建立在原表上直接進行,不會拷貝臨時表。
1. 新建一個帶有新索引的臨時表。
2. 而後鎖原表,禁止DML操做,容許讀操做。
3. 讀取彙集索引,構造新的索引項,排序並插入新索引。
4. 而後Rename,升級字典鎖,禁止讀寫。
5. 完成建立索引的操做。
能夠避免重建錶帶來的IO和CPU消耗,保證DDL期間依然有良好的性能和併發。
Inplace方式建立索引,建立過程當中,原表一樣可讀的,可是不可寫。
Online方式
這是MySQL5.6.7中提供的建立索引的方式。不管是CopyTable方式,仍是Inplace方式,建立索引的過程當中,原表只能容許讀取,不可寫。
對應用有較大的限制,所以MySQL最新版本中,InnoDB支持了所謂的Online方式建立索引。
InnoDB的Online Add Index,首先是Inplace方式建立索引,無需使用臨時表。在遍歷聚簇索引,收集記錄並插入到新索引的過程當中,原表記錄可修改。而修改的記錄保存在Row Log中。當聚簇索引遍歷完畢,並所有插入到新索引以後,重放Row Log中的記錄修改,使得新索引與聚簇索引記錄達到一致狀態。
與Copy Table方式相比,Online Add Index採用的是Inplace方式,無需Copy Table,減小了空間開銷;與此同時,Online Add Index只有在重放Row Log最後一個Block時鎖表,減小了鎖表的時間。
與Inplace方式相比,Online Add Index吸取了Inplace方式的優點,卻減小了鎖表的時間。
 
help create index;
    CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name
        [index_type]
        ON tbl_name (index_col_name,...)
        [index_option]
        [algorithm_option | lock_option] ...
    index_col_name:
        col_name [(length)] [ASC | DESC]
    index_option:
        KEY_BLOCK_SIZE [=] value
      | index_type
      | WITH PARSER parser_name
      | COMMENT 'string'
    index_type:
        USING {BTREE | HASH}
create index idx_c on sbtest1(c(20)) ALGORITHM=DEFAULT;
create index idx_c on sbtest1(c(20)) ALGORITHM=INPLACE;
寫不會阻塞,會先寫到緩存,而後完成以後同步數據;
copy的時候會阻塞寫操做
create index idx_c on sbtest1(c(20)) ALGORITHM=COPY;
innodb_online_alter_log_max_size
若是DDL執行時間很長,期間又產生了大量的dml操做,以致於超過了innodb_online_alter_log_max_size變量所指定的大小,會引發DB_ONLINE_LOG_TOO_BIG錯誤。默認爲128M,特別對於須要拷貝大表的alter操做,考慮臨時加大該值,以此得到更大的日誌緩存空間。
指定InnoDB表的聯機DDL操做期間使用的臨時日誌文件大小的上限(以字節爲單位)。每一個正在建立的索引或要更改的表都有一個這樣的日誌文件。此日誌文件存儲在DDL操做期間在表中插入,更新或刪除的數據。臨時日誌文件在須要時由innodb_sort_buffer_size的值擴展,最大爲innodb_online_alter_log_max_size指定的最大值。若是臨時日誌文件超出大小上限,則ALTER TABLE操做將失敗,而且將回滾全部未提交的併發DML操做。所以,此選項的較大值容許在聯機DDL操做期間發生更多DML,但在表被鎖定以應用日誌中的數據時,還會延長DDL操做結束時的時間段。
 
    冗餘索引
        根據最左匹配原則,一個索引是另外一個索引的子集;
        使用pt-duplicate-key-checker檢查
         select * from sys.schema_redundant_indexes;  
   無用索引:
        幾乎從未被使用過的索引
        pt-index-usage檢查低利用率索引,提供刪除建議
        select * from sys.schema_unused_indexes;    
    全表掃描
        select * from sys.schema_tables_with_full_table_scans;
 
使用索引
    一、讓MySQL自動選擇
        select ... from  t where ...
    二、建議選擇:
        select .. from t  use index(idx_name) where ...
    三、強制索引
        select ...  from t force index(idex_name) where...
 
 索引統計
    表統計信息
        show table status ;
        select * from information_schema.tables;    
        select * from mysql.innodb_table_stats;
     索引統計信息
        show index from  table;
        select * from information_schema.STATISTICS;
        select * from mysql.innodb_index_stats; 
 
 innodb_stats_auto_recalc
                默認開啓,當修改數據量大於10%,自動更新統計信息;
           innodb_stats_persistent
                默認開啓,統計信息持久化存儲;當關閉時,統計信息不持久化,每次動態採集,存儲在內存中,重啓實例(須要從新統計),不推薦
            innodb_stats_persistent_sample_pages
               統計信息持久化存儲時,默認每次採集20個page頁
           innodb_stats_on_metadata 
                默認禁用,訪問元數據時更新統計信息;
            iinnodb_stats_transient_sample_pages
                動態採集page,默認8個
 
            MySQL -A登陸不會去更新統計信息
            不接-A的話當表或者分區表比較多的時候登陸會比較慢
            use database是也須要更新統計信息,因此有時候很慢
 
執行計劃
type
ALL 掃描全表數據
index 遍歷索引
range 索引範圍查找
ref 使用非惟一索引查找數據
fulltext 使用全文索引
const 使用主鍵或者惟一索引,且匹配的結果只有一條記錄。
system const 鏈接類型的特例,查詢的表爲系統表。
possible_keys
可能使用的索引,但不必定會使用。查詢涉及到的字段上若存在索引,則該索引將被列出來。當該列爲NULL時就需考慮當前的SQL是否須要優化。
key
顯示MySQL在查詢中實際使用的索引,若沒有使用索引,顯示爲NULL。
查詢中若使用了覆蓋索引(覆蓋索引:索引的數據覆蓋了須要查詢的全部數據),則該索引僅出如今key列表中
extra
extra的信息很是豐富,常見的有: 1.Using index 使用覆蓋索引 2.Using where 使用了用where子句來過濾結果集 3.Using filesort 使用文件排序,使用非索引列進行排序時出現,很是消耗性能,儘可能優化。 4.Using temporary 使用了臨時表
 
索引不可用的狀況

    一、經過索引掃描的記錄數超過20%-30%,可能會變成全表掃描;

    二、聯合索引中,第一個索引列使用範圍查詢;(這時用的部分索引)
    三、聯合索引中,第一個查詢不是最左索引列;
    四、模糊查詢條件列最左以通配符%開始(覆蓋索引除外);
    五、兩個獨立索引,其中一個用於檢索,一個用於排序(只能用到一個索引)
    六、join查詢時,關聯列數據類型(以及字符集)不一致也會致使索引不可用
        隱式類型轉換
            u1='123' 不會轉換
            u1='a' 能夠正常走索引
        聯合索引
desc select * from t7 where name='zyq';
            desc select * from t7 where c='abc';

            desc select * from t7 where c='zyq' and pad='sdfafadfasfdaf';

desc select * from t7 where c='abc' and name='zyq';

相關文章
相關標籤/搜索