1. 程式人生 > >mysql 聚簇索引 和聚簇索引 (二級索引)的 那些事

mysql 聚簇索引 和聚簇索引 (二級索引)的 那些事

mysql的聚簇索引是指innodb引擎的特性,mysiam並沒有,如果需要該索引,只要將索引指定為主鍵(primary key)就可以了。

比如:

create table blog_user
(
  user_Name char(15) not null check(user_Name !=''),
  user_Password char(15) not null,
  user_emial varchar(20) not null unique,
  primary key(user_Name)          
  
)engine=innodb default charset=utf8 auto_increment=1;

其中的 primary key(user_Name) 這個就是聚簇索引索引了;

聚簇索引的葉節點就是資料節點,而非聚簇索引的葉節點仍然是索引節點,並保留一個連結指向對應資料塊

聚簇索引主鍵的插入速度要比非聚簇索引主鍵的插入速度慢很多。相比之下,聚簇索引適合排序,非聚簇索引(也叫二級索引)不適合用在排序的場合。 因為聚簇索引本身已經是按照物理順序放置的,排序很快。非聚簇索引則沒有按序存放,需要額外消耗資源來排序。 當你需要取出一定範圍內的資料時,用聚簇索引也比用非聚簇索引好。 另外,二級索引需要兩次索引查詢,而不是一次才能取到資料,因為儲存引擎第一次需要通過二級索引找到索引的葉子節點,從而找到資料的主鍵,然後在聚簇索引中用主鍵再次查詢索引,再找到資料。

innodb索引分類:

聚簇索引(clustered index)
    1)  有主鍵時,根據主鍵建立聚簇索引
    2)  沒有主鍵時,會用一個唯一且不為空的索引列做為主鍵,成為此表的聚簇索引
    3) 如果以上兩個都不滿足那innodb自己建立一個虛擬的聚集索引
輔助索引(secondary index)
   非聚簇索引都是輔助索引,像複合索引、字首索引、唯一索引

myisam索引:因為myisam的索引和資料是分開儲存儲存的,myisam通過key_buffer把索引先快取到記憶體中,當需要訪問資料時(通過索引訪問資料),在記憶體中直接搜尋

                         索引,然後通過索引找到磁碟相應資料,這也就是為什麼索引不在key buffer命中時,速度慢的原因  

  
innodb索引:innodb的資料和索引放在一起,當找到索引也就找到了資料

自適應雜湊索引:innodb會監控表上的索引使用情況,如果觀察到建立雜湊索引可以帶來速度的提升,那就建立雜湊索引,自 適應雜湊索引通過緩衝池的B+樹構造而來,

                               因此建立的速度很快,不需要將整個表都建雜湊索引,InnoDB 儲存引擎會自動根據訪問的頻率和模式來為某些頁建立雜湊索引。自適應雜湊索引不需要

                               儲存磁碟的,當停庫內容會丟失,資料庫起來會自己建立,慢慢維護索引。    

聚簇索引:
MySQL InnoDB一定會建立聚簇索引,把實際資料行和相關的鍵值儲存在一塊,這也決定了一個表只能有一個聚簇索引,即MySQL不會一次把資料行儲存在二個地方。

     1)  InnoDB通常根據主鍵值(primary key)進行聚簇
     2) 如果沒有建立主鍵,則會用一個唯一且不為空的索引列做為主鍵,成為此表的聚簇索引
     3) 上面二個條件都不滿足,InnoDB會自己建立一個虛擬的聚集索引


 
優點:
聚簇索引的優點,就是提高資料訪問效能。聚簇索引把索引和資料都儲存到同一棵B+樹資料結構中,並且同時將索引列與相關資料行儲存在一起。這意味著,當你訪問同一資料頁不同行記錄時,已經把頁載入到了Buffer中,再次訪問的時候,會在記憶體中完成訪問,不必訪問磁碟。不同於MyISAM引擎,它將索引和資料沒有放在一塊,放在不同的物理檔案中,索引檔案是快取在key_buffer中,索引對應的是磁碟位置,不得不通過磁碟位置訪問磁碟資料。
 
缺點:
1) 維護索引很昂貴,特別是插入新行或者主鍵被更新導至要分頁(page split)的時候。建議在大量插入新行後,選在負載較低的時間段,通過OPTIMIZE TABLE優化表,因為必須被移動的行資料可能造成碎片。使用獨享表空間可以弱化碎片
  
2) 表因為使用UUId作為主鍵,使資料儲存稀疏,這就會出現聚簇索引有可能有比全表掃面更慢,所以建議使用int的auto_increment作為主鍵 

3) 如果主鍵比較大的話,那輔助索引將會變的更大,因為輔助索引的葉子儲存的是主鍵值;過長的主鍵值,會導致非葉子節點佔用佔用更多的物理空間 
 
輔助索引
在聚簇索引之上建立的索引稱之為輔助索引,輔助索引訪問資料總是需要二次查詢。輔助索引葉子節點儲存的不再是行的物理位置,而是主鍵值。通過輔助索引首先找到的是主鍵值,再通過主鍵值找到資料行的資料葉,再通過資料葉中的Page Directory找到資料行。


複合索引
由多列建立的索引稱為符合索引,在符合索引中的前導列必須出現在where條件中,索引才會被使用
ALTER TABLE `test`.`users` ADD INDEX `idx_users_id_name` (`name`(10) ASC, `id` ASC) ;

字首索引
當索引的字串列很大時,建立的索引也就變得很大,為了減小索引體積,提高索引的掃描速度,就用索引的前部分字串索引,這樣索引佔用的空間就會大大減少,並且索引的選擇性也不會降低很多。而且是對BLOB和TEXT列進行索引,或者非常長的VARCHAR列,就必須使用字首索引,因為MySQL不允許索引它們的全部長度。

使用:
列的字首的長度選擇很重要,又要節約索引空間,又要保證字首索引的選擇性要和索引全長度選擇性接近。

唯一索引
唯一索引比較好理解,就是索引值必須唯一,這樣的索引選擇性是最好的

主鍵索引
主鍵索引就是唯一索引,不過主鍵索引是在建立表時就建立了,唯一索引可以隨時建立。

說明
主鍵和唯一索引區別
     1) 主鍵是主鍵約束+唯一索引
     2) 主鍵一定包含一個唯一索引,但唯一索引不是主鍵
     3) 唯一索引列允許空值,但主鍵列不允許空值
     4) 一個表只能有一個主鍵,但可以有多個唯一索引

索引掃描方式:
緊湊索引掃描(dense index):
在最初,為了定位資料需要做權表掃描,為了提高掃描速度,把索引鍵值單獨放在獨立的資料的資料塊裡,並且每個鍵值都有個指向原資料塊的指標,因為索引比較小,掃描索引的速度就比掃描全錶快,這種需要掃描所有鍵值的方式就稱為緊湊索引掃描

鬆散索引掃描(sparse index):
為了提高緊湊索引掃描效率,通過把索引排序和查詢演算法(B+trre),發現只需要和每個資料塊的第一行鍵值匹配,就可以判斷下一個資料塊的位置或方向,因此有效資料就是每個資料塊的第一行資料,如果把每個資料塊的第一行資料建立索引,這樣在這個新建立的索引上折半查詢,資料定位速度將更快。這種索引掃描方式就稱為鬆散索引掃描。

覆蓋索引掃描(covering index):
包含所有滿足查詢需要的資料的索引稱為覆蓋索引,即利用索引返回select列表中的欄位,而不必根據索引再次讀取資料檔案


索引相關常用命令:
1) 建立主鍵
 CREATE TABLE `pk_tab2` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `a1` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2) 建立唯一索引
create unique index indexname on tablename(columnname);
alter table tablename add unique index indexname(columnname);

3) 建立單列一般索引
create index indexname on tablename(columnname);
alter table tablename add index indexname(columnname);

4) 建立單列字首索引
create index indexname on tablename(columnname(10));    //單列的前10個字元建立字首索引
alter table tablename add index indexname(columnname(10)); //單列的前10個字元建立字首索引

5) 建立複合索引
create index indexname on tablename(columnname1,columnname2);    //多列的複合索引
create index indexname on tablename(columnname1,columnname2(10));    //多列的包含字首的複合索引
alter table tablename add index indexname(columnname1,columnname2); //多列的複合索引
alter table tablename add index indexname(columnname1,columnname(10)); //多列的包含字首的複合索引

6) 刪除索引
drop index indexname on tablename;;
alter table tablename drop  index indexname;

7) 檢視索引
show index from tablename;
show create table pk_tab2;