1. 程式人生 > >MySQL索引類型,優化,使用數據結構

MySQL索引類型,優化,使用數據結構

兩種 很好 表現 數據庫 display 找到 archive pos in子句

技術分享圖片

工欲善其事必先利其器

半藏說道:“若你在路途中遇到上帝,上帝也會被割傷。

一、mysql 索引分類(默認使用B樹結構)
在數據庫表中,對字段建立索引可以大大提高查詢速度。通過善用這些索引,可以令 MySQL的查詢和運行更加高效。索引是快速搜索的關鍵。MySQL索引的建立對於MySQL的高效運行是很重要的。下面介紹幾種常見的MySQL索引類型。
1、普通型索引
這是最基本的索引類型,而且它沒有唯一性之類的限制。普通索引可以通過以下幾種方式創建:

(1)創建索引,例如CREATE INDEX 索引的名字 ON tablename (列名1,列名2,...);
(2)修改表,例如ALTER TABLE tablename ADD INDEX 索引的名字 (列名1,列名2,...);


(3)創建表的時候指定索引,例如CREATE TABLE tablename ( [...], INDEX 索引的名字 (列名1,列名
2,...) );
2、唯一索引
這種索引和前面的“普通索引”基本相同,但有一個區別:索引列的所有值都只能出現一次,即必須唯一。唯一性索引可以用以下幾種方式創建:

(1)創建索引,例如CREATE UNIQUE INDEX 索引的名字 ON tablename (列的列表);
(2)修改表,例如ALTER TABLE tablename ADD UNIQUE 索引的名字 (列的列表);
(3)創建表的時候指定索引,例如CREATE TABLE tablename ( [...], UNIQUE 索引的名字 (列的列

表) );
3、主鍵
主鍵是一種唯一性索引,但它必須指定為“PRIMARY KEY”。如果你曾經用過AUTO_INCREMENT類型的列,你可能已經熟悉主鍵之類的概念了。主鍵一般在創建表的時候指定,例如“CREATE TABLE tablename ( [...], PRIMARY KEY (列的列表) ); ”。但是,我們也可以通過修改表的方式加入主鍵,例如“ALTER TABLE tablename ADD PRIMARY KEY (列的列表); ”。每個表只能有一個主鍵。 (主鍵相當於聚合索引,是查找最快的索引)

4、單列索引和多列索引
索引可以是單列索引,也可以是多列索引。

(1)單列索引就是常用的一個列字段的索引,常見的索引。

(2)多列索引就是含有多個列字段的索引
alter table student add index sy(name,age,score);
索引sy就為多列索引,多列索引在以下幾中情況下才能有效:
select * from student where name=‘jia‘ and age>=‘12‘ //where條件中含有索引的首列字段和
第二個字段
select * from student where name=‘jia‘ //where條件中只含有首列字段
select * from student where name=‘jia‘ and score<60//where條件中含有首列字段和第三個字

總結:多列索引只有在where條件中含有索引中的首列字段時才有效
5、選擇索引列
應該怎樣選擇索引列,首先要看查詢條件,一般將查詢條件中的列作為索引

二、索引列的優化
選擇索引列:


1、性能優化過程中,選擇在哪個列上創建索引是最重要的步驟之一。可以考慮使用索引的主要有

  兩種類型的列:在where子句中出現的列,在join子句中出現的列。

2、考慮列中值的分布,索引的列的基數越大,索引的效果越好。

3、使用短索引,如果對字符串列進行索引,應該指定一個前綴長度,可節省大量索引空間,提升查詢速度。

4、利用最左前綴

5、不要過度索引,只保持所需的索引。每個額外的索引都要占用額外的磁盤空間,並降低寫操作的性能。

  在修改表的內容時,索引必須進行更新,有時可能需要重構,因此,索引越多,所花的時間越長。

  MySQL只對一下操作符才使用索引:<,<=,=,>,>=,between,in,

  以及某些時候的like(不以通配符%或_開頭的情形)。

三、使用的數據結構

如大家所知道的,Mysql目前主要有以下幾種索引類型:FULLTEXT,HASH,BTREE,RTREE。

那麽,這幾種索引有什麽功能和性能上的不同呢?

1、FULLTEXT

即為全文索引,目前只有MyISAM引擎支持。其可以在CREATE TABLE ,ALTER TABLE ,CREATE INDEX 使用,不過目前只有 CHAR、VARCHAR ,TEXT 列上可以創建全文索引。值得一提的是,在數據量較大時候,現將數據放入一個沒有全局索引的表中,然後再用CREATE INDEX創建FULLTEXT索引,要比先為一張表建立FULLTEXT然後再將數據寫入的速度快很多。

全文索引並不是和MyISAM一起誕生的,它的出現是為了解決WHERE name LIKE “%word%"這類針對文本的模糊查詢效率較低的問題。在沒有全文索引之前,這樣一個查詢語句是要進行遍歷數據表操作的,可見,在數據量較大時是極其的耗時的,如果沒有異步IO處理,進程將被挾持,很浪費時間,當然這裏不對異步IO作進一步講解,想了解的童鞋,自行谷哥。

全文索引的使用方法並不復雜:

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

使用SELECT * FROM table WHERE MATCH(cname1[,cname2…]) AGAINST (‘word‘ 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這個詞,可以說,自打我們開始碼的那一天起,就開始不停地見到和使用到了。其實,hash就是一種(key=>value)形式的鍵值對,如數學中的函數映射,允許多個key對應相同的value,但不允許一個key對應多個value。正是由於這個特性,hash很適合做索引,為某一列或幾列建立hash索引,就會利用這一列或幾列的值通過一定的算法計算出一個hash值,對應一行或幾行數據(這裏在概念上和函數映射有區別,不要混淆)。在java語言中,每個類都有自己的hashcode()方法,沒有顯示定義的都繼承自object類,該方法使得每一個對象都是唯一的,在進行對象間equal比較,和序列化傳輸中起到了很重要的作用。hash的生成方法有很多種,足可以保證hash碼的唯一性,例如在MongoDB中,每一個document都有系統為其生成的唯一的objectID(包含時間戳,主機散列值,進程PID,和自增ID)也是一種hash的表現。額,我好像扯遠了-_-!

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

在這裏愚安就不自己總結了。引用下園子裏其他大神的文章:來自 14的路 的MySQL的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索引的過程,順便解釋下上面的第4,5條:

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

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

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

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

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

3、BTREE

BTREE索引就是一種將索引值按一定的算法,存入一個樹形的數據結構中,相信學過數據結構的童鞋都對當初學習二叉樹這種數據結構的經歷記憶猶新,反正愚安我當時為了軟考可是被這玩意兒好好地折騰了一番,不過那次考試好像沒怎麽考這個。如二叉樹一樣,每次查詢都是從樹的入口root開始,依次遍歷node,獲取leaf。

BTREE在MyISAM裏的形式和Innodb稍有不同

在 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的優勢在於範圍查找.

各種索引的使用情況

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

(2)由於FULLTEXT對中文支持不是很好,在沒有插件的情況下,最好不要使用。其實,一些小的博客應用,只需要在數據采集時,為其建立關鍵字列表,通過關鍵字索引,也是一個不錯的方法,至少愚安我是經常這麽做的。

(3)對於一些搜索引擎級別的應用來說,FULLTEXT同樣不是一個好的處理方法,Mysql的全文索引建立的文件還是比較大的,而且效率不是很高,即便是使用了中文分詞插件,對中文分詞支持也只是一般。真要碰到這種問題,Apache的Lucene或許是你的選擇。

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

(5)至於RTREE,了解不多

參考鏈接:

https://www.cnblogs.com/cq-home/p/3482101.html

https://www.cnblogs.com/yuan-shuai/p/3225417.html

圖片引自:Kill Bill 1

MySQL索引類型,優化,使用數據結構