MySQL索引分類
1、主鍵索引:設定為主鍵后數據庫會自動建立索引,innodb為聚簇索引
語法:
隨表一起建索引:
CREATE TABLE customer (id INT(10) UNSIGNED AUTO_INCREMENT ,customer_no VARCHAR(200),customer_name VARCHAR(200),
PRIMARY KEY(id)
);
unsigned (無符號的)
使用 AUTO_INCREMENT 關鍵字的列必須有索引(只要有索引就行)。
CREATE TABLE customer2 (id INT(10) UNSIGNED ,customer_no VARCHAR(200),customer_name VARCHAR(200),
PRIMARY KEY(id)
);
單獨建主鍵索引:
ALTER TABLE customer
add PRIMARY KEY customer(customer_no);
刪除建主鍵索引:
ALTER TABLE customer
drop PRIMARY KEY ;
修改建主鍵索引:
必須先刪除掉(drop)原索引,再新建(add)索引
2、單值索引:即一個索引只包含單個列,一個表可以有多個單列索引
隨表一起建索引:
CREATE TABLE customer (id INT(10) UNSIGNED AUTO_INCREMENT ,customer_no VARCHAR(200),customer_name VARCHAR(200),
PRIMARY KEY(id),
KEY (customer_name)
);
隨表一起建立的索引 索引名同 列名(customer_name)
單獨建單值索引:
CREATE INDEX idx_customer_name ON customer(customer_name);
刪除索引:
DROP INDEX idx_customer_name ;
3、唯一索引:索引列的值必須唯一,但允許有空值
隨表一起建索引:
CREATE TABLE customer (id INT(10) UNSIGNED AUTO_INCREMENT ,customer_no VARCHAR(200),customer_name VARCHAR(200),
PRIMARY KEY(id),
KEY (customer_name),
UNIQUE (customer_no)
);
建立 唯一索引時必須保證所有的值是唯一的(除了null),若有重復數據,會報錯。
單獨建唯一索引:
CREATE UNIQUE INDEX idx_customer_no ON customer(customer_no);
刪除索引:
DROP INDEX idx_customer_no on customer ;
4、復合索引:即一個索引包含多個列
隨表一起建索引:
CREATE TABLE customer (id INT(10) UNSIGNED AUTO_INCREMENT ,customer_no VARCHAR(200),customer_name VARCHAR(200),
PRIMARY KEY(id),
KEY (customer_name),
UNIQUE (customer_name),
KEY (customer_no,customer_name)
);
單獨建索引:
CREATE INDEX idx_no_name ON customer(customer_no,customer_name);
刪除索引:
DROP INDEX idx_no_name on customer ;
5、基本語法
創建:
ALTER mytable ADD [UNIQUE ] INDEX [indexName] ON (columnname(length))
刪除:
DROP INDEX [indexName] ON mytable;
查看:
SHOW INDEX FROM table_name\G
non_unique: 是否是唯一索引 1:是 0:不是
seq_in_index:列 在索引中的 序列。針對符合索引(一個索引對應多個列)。針對同一個復合索引 按照創建復合索引時的順序進行排序
collation:
cardinality:
sub_part:
packed:
Null:是否允許 null 值
comment:
index_comment:
使用ALTER命令:
有四種方式來添加數據表的索引:
ALTER TABLE tbl_name ADD PRIMARY KEY (column_list): 該語句添加一個主鍵,這意味着索引值必須是唯一的,且不能為NULL。
ALTER TABLE tbl_name ADD UNIQUE index_name (column_list): 這條語句創建索引的值必須是唯一的(除了NULL外,NULL可能會出現多次)。
ALTER TABLE tbl_name ADD INDEX index_name (column_list): 添加普通索引,索引值可出現多次。
ALTER TABLE tbl_name ADD FULLTEXT index_name (column_list):該語句指定了索引為 FULLTEXT ,用於全文索引。
mysql索引結構
1、BTree索引(Myisam普通索引)
原理圖:
【初始化介紹】
一顆b樹,淺藍色的塊我們稱之為一個磁盤塊,可以看到每個磁盤塊包含幾個數據項(深藍色所示)和指針(黃色所示),
如磁盤塊1包含數據項17和35,包含指針P1、P2、P3,
P1表示小於17的磁盤塊,P2表示在17和35之間的磁盤塊,P3表示大於35的磁盤塊。
真實的數據存在於葉子節點即3、5、9、10、13、15、28、29、36、60、75、79、90、99。
非葉子節點不存儲真實的數據,只存儲指引搜索方向的數據項,如17、35並不真實存在於數據表中。
【查找過程】
如果要查找數據項29,那么首先會把磁盤塊1由磁盤加載到內存,此時發生一次IO,在內存中用二分查找確定29在17和35之間,鎖定磁盤塊1的P2指針,內存時間因為非常短(相比磁盤的IO)可以忽略不計,通過磁盤塊1的P2指針的磁盤地址把磁盤塊3由磁盤加載到內存,發生第二次IO,29在26和30之間,鎖定磁盤塊3的P2指針,通過指針加載磁盤塊8到內存,發生第三次IO,同時內存中做二分查找找到29,結束查詢,總計三次IO。
真實的情況是,3層的b+樹可以表示上百萬的數據,如果上百萬的數據查找只需要三次IO,性能提高將是巨大的,如果沒有索引,每個數據項都要發生一次IO,那么總共需要百萬次的IO,顯然成本非常非常高。
關於時間復雜度:同一問題可用不同算法解決,而一個算法的質量優劣將影響到算法乃至程序的效率。算法分析的目的在於選擇合適算法和改進算法。
1 N logN 分別表示數據與查詢次數之間的關系。
常數 1*c 表示查詢最快的方式。查詢次數不隨數據的增加而增加
變量 N 表示查詢次數隨數據數量的增加而增加
對數 logN 表示查詢次數與數據數量成對數關系。 介於常數與 N 之間。
n*logN 表示使用的復合方法。
2、B+Tree索引(innodb的普通索引)
原理圖:
B+TREE 第二級的 數據並不能直接取出來,只作索引使用。在內存有限的情況下,查詢效率高於 B-TREE
B-TREE 第二級可以直接取出來,樹形結構比較重,在內存無限大的時候有優勢。
B樹和B+樹的區別:
B+Tree與B-Tree 的區別:結論在內存有限的情況下,B+TREE 永遠比 B-TREE好。無限內存則后者方便
1)B-樹的關鍵字和記錄是放在一起的,葉子節點可以看作外部節點,不包含任何信息;B+樹葉子節點中只有關鍵字和指向下一個節點的索引,記錄只放在葉子節點中。(一次查詢可能進行兩次i/o操作)
2)在B-樹中,越靠近根節點的記錄查找時間越快,只要找到關鍵字即可確定記錄的存在;而B+樹中每個記錄的查找時間基本是一樣的,都需要從根節點走到葉子節點,而且在葉子節點中還要再比較關鍵字。從這個角度看B-樹的性能好像要比B+樹好,而在實際應用中卻是B+樹的性能要好些。因為B+樹的非葉子節點不存放實際的數據,這樣每個節點可容納的元素個數比B-樹多,樹高比B-樹小,這樣帶來的好處是減少磁盤訪問次數。盡管B+樹找到一個記錄所需的比較次數要比B-樹多,但是一次磁盤訪問的時間相當於成百上千次內存比較的時間,因此實際中B+樹的性能可能還會好些,而且B+樹的葉子節點使用指針連接在一起,方便順序遍歷(例如查看一個目錄下的所有文件,一個表中的所有記錄等),這也是很多數據庫和文件系統使用B+樹的緣故。
思考:為什么說B+樹比B-樹更適合實際應用中操作系統的文件索引和數據庫索引?
1) B+樹的磁盤讀寫代價更低
B+樹的內部結點並沒有指向關鍵字具體信息的指針。因此其內部結點相對B 樹更小。如果把所有同一內部結點的關鍵字存放在同一盤塊中,那么盤塊所能容納的關鍵字數量也越多。一次性讀入內存中的需要查找的關鍵字也就越多。相對來說IO讀寫次數也就降低了。
2) B+樹的查詢效率更加穩定
由於非終結點並不是最終指向文件內容的結點,而只是葉子結點中關鍵字的索引。所以任何關鍵字的查找必須走一條從根結點到葉子結點的路。所有關鍵字查詢的路徑長度相同,導致每一個數據的查詢效率相當。
3、聚簇索引與非聚簇索引
聚簇索引並不是一種單獨的索引類型,而是一種數據存儲方式。
術語‘聚簇’表示數據行和相鄰的鍵值進錯的存儲在一起。
如下圖,左側的索引就是聚簇索引,因為數據行在磁盤的排列和索引排序保持一致。
聚簇索引的好處:
- 按照聚簇索引排列順序,查詢顯示一定范圍數據的時候,由於數據都是緊密相連,數據庫不用從多個數據塊中提取數據,所以節省了大量的io操作。
聚簇索引的限制:
- 對於mysql數據庫目前只有innodb數據引擎支持聚簇索引,而Myisam並不支持聚簇索引。
- 由於數據物理存儲排序方式只能有一種,所以每個Mysql的表只能有一個聚簇索引。一般情況下就是該表的主鍵。
- 為了充分利用聚簇索引的聚簇的特性,所以innodb表的主鍵列盡量選用有序的順序id,而不建議用無序的id,比如uuid這種。(參考聚簇索引的好處。)
這里說明了主鍵索引為何采用自增的方式:1、業務需求,有序。2、能使用到聚簇索引
4、full-text全文索引
全文索引(也稱全文檢索)是目前搜索引擎使用的一種關鍵技術。它能夠利用【分詞技術】等多種算法智能分析出文本文字中關鍵詞的頻率和重要性,然后按照一定的算法規則智能地篩選出我們想要的搜索結果。
CREATE TABLE `article` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(200) DEFAULT NULL,
`content` text,
PRIMARY KEY (`id`),
FULLTEXT KEY `title` (`title`,`content`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
不同於like方式的的查詢:
SELECT * FROM article WHERE content LIKE ‘%查詢字符串%’;
全文索引用match+against方式查詢:
SELECT * FROM article WHERE MATCH(title,content) AGAINST (‘查詢字符串’);
明顯的提高查詢效率。
限制:
mysql5.6.4以前只有Myisam支持,5.6.4版本以后innodb才支持,但是官方版本不支持中文分詞,需要第三方分詞插件。
5.7以后官方支持中文分詞。
隨着大數據時代的到來,關系型數據庫應對全文索引的需求已力不從心,逐漸被 solr,elasticSearch等專門的搜索引擎所替代。
5、Hash索引
Hash索引只有Memory, NDB兩種引擎支持,Memory引擎默認支持Hash索引,如果多個hash值相同,出現哈希碰撞,那么索引以鏈表方式存儲。
NoSql采用此中索引結構。
6、R-Tree索引
R-Tree在mysql很少使用,僅支持geometry數據類型,支持該類型的存儲引擎只有myisam、bdb、innodb、ndb、archive幾種。
相對於b-tree,r-tree的優勢在於范圍查找。
索引的使用場景
1、哪些情況需要創建索引
(1)主鍵自動建立唯一索引
(2)頻繁作為查詢條件的字段應該創建索引(where 后面的語句)
(3)查詢中與其它表關聯的字段,外鍵關系建立索引
A 表關聯 B 表:A join B 。 on 后面的連接條件 既 A 表查詢 B 表的條件。所以 B 表被關聯的字段建立索引能大大提高查詢效率
因為在 join 中,join 左邊的表會用每一個字段去遍歷 B 表的所有的關聯數據,相當於一個查詢操作
(4)單鍵/組合索引的選擇問題,who?(在高並發下傾向創建組合索引)
(5)查詢中排序的字段,排序字段若通過索引去訪問將大大提高排序速度
group by 和 order by 后面的字段有索引大大提高效率
(6)查詢中統計或者分組字段
2、哪些情況不要創建索引
(1)表記錄太少
(2)經常增刪改的表
Why:提高了查詢速度,同時卻會降低更新表的速度,如對表進行INSERT、UPDATE和DELETE。
因為更新表時,MySQL不僅要保存數據,還要保存一下索引文件
(3)Where條件里用不到的字段不創建索引
索引建多了影響 增刪改 的效率
(4)數據重復且分布平均的表字段,因此應該只為最經常查詢和最經常排序的數據列建立索引。注意,如果某個數據列包含許多重復的內容,為它建立索引就沒有太大的實際效果。