mysql 不同索引的區別和適用情況總結


MySQL目前主要有以下幾種索引類型:

 

 

  • 普通索引 INDEX 允許出現相同的索引內容 (normal)

 

 

  • 唯一索引 UNIQUE 不可以出現相同的值,可以有NULL值
  • 主鍵索引 PROMARY KEY 不允許出現相同的值(唯一性,且只能有一個)
  • 組合索引 實質上是將多個字段建到一個索引里,列值的組合必須唯一

 

 

  • 全文索引 FULLTEXT INDEX 可以針對值中的某個單詞,但效率低(不建議,可利用添加關鍵詞關聯列來實現)

 

 

 

 

//建表時建立
CREATE TABLE table_name[col_name data type] [unique
|fulltext][index|key][index_name](col_name[length])[asc|desc]
注意:復合索引使用時要與索引名和關聯的列一一對應,如果想單獨對某個列進行索引操作,需要新建個以獨立的索引

 

說明

1.unique|fulltext為可選參數,分別表示唯一索引、全文索引
2.index和key為同義詞,兩者作用相同,用來指定創建索引
3.col_name為需要創建索引的字段列,該列必須從數據表中該定義的多個列中選擇
4.index_name指定索引的名稱,為可選參數,如果不指定,默認col_name為索引值
5.length為可選參數,表示索引的長度,只有字符串類型的字段才能指定索引長度
6.asc或desc指定升序或降序的索引值存儲

 

索引的創建、修改、刪除

1、使用ALTER TABLE 語句創建索引

應用於表創建完成之后添加索引

ALTER TABLE 表名 ADD 索引類型 (unique,primary key,fulltext,index)[索引名](字段名)
//普通索引
alter table table_name add index index_name (column_list) ;
//唯一索引
alter table table_name add unique (column_list) ;
//主鍵索引
alter table table_name add primary key (column_list) ;

說明:
ALTER TABLE可用於創建普通索引、UNIQUE索引和PRIMARY KEY索引3種索引格式,
table_name是要增加索引的表名,column_list指出對哪些列進行索引,多列時各列之間用逗號分隔。
索引名index_name可選,缺省時,MySQL將根據第一個索引列賦一個名稱。另外,ALTER TABLE允許在單個語句中更改多個表,因此可以同時創建多個索引。

 

2、使用CREATE INDEX 對表增加索引

CREATE INDEX可用於對表增加普通索引或UNIQUE索引,可用於建表時創建索引。

CREATE INDEX index_name ON table_name(username(length)); 

如果是CHAR,VARCHAR類型,length可以小於字段實際長度;如果是BLOB和TEXT類型,必須指定 length。
//create只能添加這兩種索引;
CREATE INDEX index_name ON table_name (column_list)
CREATE UNIQUE INDEX index_name ON table_name (column_list)
table_name、index_name和column_list具有與ALTER TABLE語句中相同的含義,索引名不可選。另外,不能用CREATE INDEX語句創建PRIMARY KEY索引

 

3、刪除索引

 刪除索引可以使用ALTER TABLE或DROP INDEX語句來實現。DROP INDEX可以在ALTER TABLE內部作為一條語句處理。

drop index index_name on table_name ;
alter table table_name drop index index_name ;
alter table table_name drop primary key ;

在前面的兩條語句中,都刪除了table_name中的索引index_name。而在最后一條語句中,只在刪除PRIMARY KEY索引中使用,因為一個表只可能有一個PRIMARY KEY索引,因此不需要指定索引名。如果沒有創建PRIMARY KEY索引,但表具有一個或多個UNIQUE索引,則MySQL將刪除第一個UNIQUE索引。

如果從表中刪除某列,則索引會受影響。對於多列組合的索引,如果刪除其中的某列,則該列也會從索引中刪除。如果刪除組成索引的所有列,則整個索引將被刪除。

 

4、修改索引

mysql 是沒有內置修改索引操作的,需要先執行刪除操作在重新建立一個索引

 

5、查看索引

-如果查看索引前,沒有使用use db_name等命令指定具體的數據庫,則必須加上FROM db_name
SHOW INDEX FROM table_name [FROM db_name]
--如果查看索引前,沒有使用use db_name等命令指定具體的數據庫,則必須加上db_name.前綴
SHOW INDEX FROM [db_name.]table_name

--如果查看索引前,使用了use db_name等命令指定具體的數據庫
SHOW INDEX FROM table_name

 

 

組合索引與前綴索引

組合索引和前綴索引是對建立索引技巧的一種稱呼,並不是索引的類型。

create table dm_user
(
   ID                   int not null auto_increment comment '主鍵',
   LOGIN_NAME           varchar(30) not null comment '登錄名',
   PASSWORD             varchar(30) not null comment '密碼',
   CITY                 varchar(30) not null comment '城市',
   AGE                  int not null comment '年齡',
   SEX                  int not null comment '性別(0:女 1:男)',
   primary key (ID)
);

comment  表示添加注釋(注意中文亂碼的問題,需要設置表的編碼格式為utf-8)

建立組合索引,即將LOGIN_NAME,CITY建到一個索引里

ALTER TABLE md_user ADD INDEX name_city (LOGIN_NAME(16),CITY); 

建表時,LOGIN_NAME長度為30,這里用16,是因為一般情況下名字的長度不會超過16,這樣會加快索引查詢速度,還會減少索引文件的大小,提高INSERT,UPDATE的更新速度。

 

 

 

值得一提的是,mysql組合索引是依據“最左前綴”的形式產生索引結果的。簡單的理解就是只從最左邊的開始組合,並不是只要包含這幾列的查詢都會用到該組合索引。也就是說index_name(column1(length),column2,column3...)從左到右進行索引,如果沒有左前索引,mysql不會執行索引查詢

ALTER TABLE table_name ADD INDEX index_name (column1,column2,column3,column4); 

//相當於分別創建了一下幾種組合索引
column1,column2,column3,column4
column1,column2,column3
column1,column2
column1

 

如果索引列長度過長,這種列索引時將會產生很大的索引文件,不便於操作,可以使用前綴索引方式進行索引,前綴索引應該控制在一個合適的點,控制在0.31黃金值即可(大於這個值就可以創建)。

SELECT COUNT(DISTINCT(LEFT(`column_name`,10)))/COUNT(*) FROM table_name; -- 這個值大於0.31就可以創建前綴索引,Distinct去重復

ALTER TABLE `table_name` ADD INDEX `uname`(column_name(10)); -- 增加前綴索引SQL,將列名的索引建立在10,這樣可以減少索引文件大小,加快索引查詢速度

Mysql字符串截取函數:left()、right()、substring()、substring_index()

 

索引類型

1、FULLTEXT

全文索引,目前只有MyISAM引擎支持,mysql 5.6之后InnoDB引擎也支持。其可以在CREATE TABLE ,ALTER TABLE ,CREATE INDEX 使用,不過目前只有 CHAR、VARCHAR ,TEXT 列上可以創建全文索引。

注意:在數據量較大時候,先將數據放入一個沒有全文索引的表中,然后再用CREATE INDEX創建FULLTEXT索引,要比先為一張表建立FULLTEXT然后再將數據寫入的速度快很多。

全文索引的出現是為了解決WHERE name LIKE “%keyword%"這類針對文本的模糊查詢效率較低的問題。

在數據量較大時是查詢是極其的耗時的,如果沒有異步IO處理,進程將被挾持,很浪費時間。想了解異步IO的,自行谷歌。

全文索引的使用:

創建ALTER TABLE table ADD INDEX `FULLINDEX` USING FULLTEXT(`cname1`[,cname2…]);

使用SELECT * FROM table WHERE MATCH(cname1[,cname2…]) AGAINST ('keyword' MODE );

其中, MODE為搜尋方式(IN BOOLEAN MODE ,IN NATURAL LANGUAGE MODE ,IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION / WITH QUERY EXPANSION)。

關於這三種搜尋方式,簡單地說分為:

  • 布爾模式,允許word里含一些特殊字符用於標記一些具體的要求,如+表示一定要有,-表示一定沒有,*表示通用匹配符,類似正則;
  • 自然語言模式,就是簡單的單詞匹配;
  • 含表達式的自然語言模式,就是先用自然語言模式處理,對返回的結果,再進行表達式匹配。

FULLTEXT索引也是按照分詞原理建立索引的。西文中,大部分為字母文字,分詞可以很方便的按照空格進行分割。

但很中文不能按照這種方式進行分詞。那又怎么辦呢?利用Mysql的中文分詞插件Mysqlcft,就可以對中文進行分詞,Mysqlcft詳情。

 

2、HASH

hash就是一種(key=>value)形式的鍵值對,如數學中的函數映射,允許多個key對應相同的value,但不允許一個key對應多個value。正是由於這個特性,hash很適合做索引,為某一列或幾列建立hash索引,就會利用這一列或幾列的值通過一定的算法計算出一個hash值,對應一行或幾行數據(這里在概念上和函數映射有區別,不要混淆)。在java語言中,每個類都有自己的hashcode()方法,沒有顯示定義的都繼承自object類,該方法使得每一個對象都是唯一的,在進行對象間equal比較,和序列化傳輸中起到了很重要的作用。

hash的生成方法有很多種,可以保證hash碼的唯一性。如在MongoDB中,每一個document都有系統為其生成的唯一的objectID(包含時間戳,主機散列值,進程PID,和自增ID)也是一種hash的表現。

由於hash索引可以一次定位,不需要像樹形索引那樣逐層查找,因此具有極高的效率。

那為什么還需要其他的樹形索引呢?

這里簡單說下樹形索引Btree 與 Hash 索引的區別:

(1)Hash 索引僅能滿足"=","IN"和"<=>"查詢,不能使用范圍查詢。 
由於 Hash 索引比較的是進行 Hash 運算之后的 Hash 值,所以它只能用於等值的過濾,不能用於基於范圍的過濾,因為經過相應的 Hash 算法處理之后的 Hash 值的大小關系,並不能保證和Hash運算前完全一樣。 

(2)Hash 索引無法被用來避免數據的排序操作。 
由於 Hash 索引中存放的是經過 Hash 計算之后的 Hash 值,而且Hash值的大小關系並不一定和 Hash 運算前的鍵值完全一樣,所以數據庫無法利用索引的數據來避免任何排序運算; 

(3)Hash 索引不能利用部分索引鍵查詢。 
對於組合索引,Hash 索引在計算 Hash 值的時候是組合索引鍵合並后再一起計算 Hash 值,而不是單獨計算 Hash 值,所以通過組合索引的前面一個或幾個索引鍵進行查詢的時候,Hash 索引也無法被利用。 

(4)Hash 索引在任何時候都不能避免表掃描。 
Hash 索引是將索引鍵通過 Hash 運算之后,將 Hash運算結果的 Hash 值和所對應的行指針信息存放於一個 Hash 表中,由於不同索引鍵存在相同 Hash 值,所以即使取滿足某個 Hash 鍵值的數據的記錄條數,也無法從 Hash 索引中直接完成查詢,還是要通過訪問表中的實際數據進行相應的比較,並得到相應的結果。 

(5)Hash 索引遇到大量Hash值相等的情況后性能並不一定就會比B-Tree索引高。 
對於選擇性比較低的索引鍵,如果創建 Hash 索引,那么將會存在大量記錄指針信息存於同一個 Hash 值相關聯。這樣要定位某一條記錄時就會非常麻煩,會浪費多次表數據的訪問,而造成整體性能低下。

 

HASH索引的過程,當我們為某一列或某幾列建立hash索引時(目前就只有MEMORY引擎顯式地支持這種索引),會在硬盤上生成類似如下的文件:

hash值  存儲地址    
1db54bc745a1 77#45b5 
4bca452157d4 76#4556,77#45cc…

hash值即為通過特定算法由指定列數據計算出來,磁盤地址即為所在數據行存儲在硬盤上的地址(也有可能是其他存儲地址,其實MEMORY會將hash表導入內存)。

當進行WHERE num= 18 查詢時,會將18通過相同的算法計算出一個hash值==>在hash表中找到對應的儲存地址==>根據存儲地址取得數據。

所以,每次查詢時都要遍歷hash表,直到找到對應的hash值,如第(4)區別中描述的,數據量大了之后,hash表也會變得龐大起來,性能下降,遍歷耗時增加,如第(5)區別。

 

3、BTREE

BTREE樹形索引就是一種將索引值按一定的算法,存入一個樹形的數據結構中,學過數據結構的對於二叉樹這種數據結構應該不陌生吧。如二叉樹一樣,每次查詢都是從樹的入口root開始,依次遍歷node,獲取leaf。

BTREE在MyISAM里的形式和Innodb稍有不同(雖然兩者都使用B+Tree作為索引結構,但還是有些區別的,數據庫優化-mysql中INNODB和MYIASM引擎的區別

在 Innodb里,有兩種形態:一是primary key形態,其leaf node里存放的是數據,而且不僅存放了索引鍵的數據,還存放了其他字段的數據。二是secondary index,其leaf node和普通的BTREE差不多,只是還存放了指向主鍵的信息.

而在MyISAM里,主鍵和其他的並沒有太大區別。不過和Innodb不太一樣的地方是在MyISAM里,leaf node里存放的不是主鍵的信息,而是指向數據文件里的對應數據行的地址信息.

 

4、RTREE

RTREE在mysql很少使用,僅支持geometry數據類型(幾何數據),支持該類型的存儲引擎只有MyISAM、BDb、InnoDb、NDb、Archive幾種。

相對於BTREE,RTREE的優勢在於范圍查找.

 

 

索引的缺點:

  • 雖然索引大大提高了查詢速度,同時卻會降低更新表的速度,如對表進行insert、update和delete。因為更新表時,不僅要保存數據,還要保存一下索引文件。
  • 建立索引會占用磁盤空間的索引文件。一般情況這個問題不太嚴重,但如果你在一個大表上創建了多種組合索引,索引文件的會增長很快。
    索引只是提高效率的一個因素,如果有大數據量的表,就需要花時間研究建立最優秀的索引,或優化查詢語句。

 

注意事項和設計技巧:

1.索引不會包含有null值的列

只要列中包含有null值都將不會被包含在索引中,組合索引中只要有一列含有null值,那么這一列對於此復合索引就是無效的。所以我們在數據庫設計時不要讓字段的默認值為null。

2.使用短索引

對串列進行索引,如果可能應該指定一個前綴長度。例如,如果有一個char(255)的列,如果在前10個或20個字符內,多數值是惟一的,那么就不要對整個列進行索引。短索引不僅可以提高查詢速度而且可以節省磁盤空間和I/O操作。

3.索引列排序

查詢只使用一個索引,因此如果where子句中已經使用了索引的話,那么order by中的列是不會使用索引的。因此數據庫默認排序可以符合要求的情況下不要使用排序操作;盡量不要包含多個列的排序,如果需要最好給這些列創建復合索引。

4.like語句操作
一般情況下不推薦使用like操作,如果非使用不可,如何使用也是一個問題。like “%aaa%” 不會使用索引而like “aaa%”可以使用索引。

5.不要在列上進行運算

這將導致索引失效而進行全表掃描

6.不使用not in和<>判斷操作

NOT IN 、<>、!=不使用索引,但<,<=,=,>,>=,BETWEEN,IN是可以用到索引的。

not in和<> 這將導致索引失效,可以考慮使用exists 或 not exists 來代替in 和 not in (注意 in操作 是可以利用索引的)。

mysql中的in語句是把外表和內表作hash 連接,而exists語句是對外表作loop循環,每次loop循環再對內表進行查詢。一直大家都認為exists比in語句的效率要高,這種說法其實是不准確的。這個是要區分環境的。

簡而言之就是,內查詢循環次數少(即內查詢表數據少於外查詢表或相差不大的情況)使用exists  效率高;反之,外查詢循環次數少(即外查詢表遠少於內查詢表數據)使用in 效率高。

not in 和not exists如果查詢語句使用了not in 那么內外表都進行全表掃描,沒有用到索引;而not extsts 的子查詢依然能用到表上的索引。所以無論那個表大,用not exists都比not in要快。 

使用between and  區間 來代替<>判斷操作。

7、EXPLAIN可以幫助開發人員分析SQL問題.

explain顯示了mysql如何使用索引來處理select語句以及連接表,可以幫助選擇更好的索引和寫出更優化的查詢語句。使用方法,在select語句前加上Explain就可以。

8、索引要建立在值比較唯一的字段上

9、索引要建立在經常進行select操作的字段上。

這是因為,如果這些列很少用到,那么有無索引並不能明顯改變查詢速度。相反,由於增加了索引,反而降低了系統的維護速度和增大了空間需求。

10、對於那些定義為text、image和bit數據類型的列不應該增加索引。因為這些列的數據量要么相當大,要么取值很少。

11、在where和join中出現的列需要建立索引

12、如果where字句的查詢條件里使用了函數(如:where YEAR(column)=…),mysql將無法使用索引

13、在join操作中(需要從多個數據表提取數據時),mysql只有在主鍵和外鍵的數據類型相同時才能使用索引,否則及時建立了索引也不會使用。

14、當where條件中存在 字符串與數字比較時(數據類型相同)不使用索引,用到OR 關鍵詞時也不會使用索引

 

 

各種索引的使用情況

(1)對於BTREE這種Mysql默認的索引類型,具有普遍的適用性

(2)由於FULLTEXT對中文支持不是很好,在沒有插件的情況下,最好不要使用。在小的博客應用,在數據采集時,為其建立關鍵字列表,通過關鍵字索引也可以起到類型的作用。

(3)對於一些搜索引擎級別的應用來說,FULLTEXT同樣不是一個好的處理方法,Mysql的全文索引建立的文件還是比較大的,而且效率不是很高。Apache的Lucene或許是你的選擇。

(4)正是因為hash表在處理較小數據量時具有無可比擬的素的優勢,所以hash索引很適合做緩存(內存數據庫)。如mysql數據庫的內存版本Memsql,使用量很廣泛的緩存工具Mencached,NoSql數據庫redis等,都使用了hash索引這種形式。Mysql的MEMORY引擎也是可以滿足這種需求的。

 

在實際操作過程中,應該選取表中哪些字段作為索引?

為了使索引的使用效率更高,在創建索引時,必須考慮在哪些字段上創建索引和創建什么類型的索引,有7大原則:

1.選擇唯一性索引
2.為經常需要排序、分組和聯合操作的字段建立索引
3.為常作為查詢條件的字段建立索引
4.限制索引的數目
5.盡量使用數據量少的索引
6.盡量使用前綴來索引
7.刪除不再使用或者很少使用的索引

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM