Mysql索引

Mysql索引

A、索引的基本操做mysql

1、概念算法

1)、查看索引 show index from 數據庫表名 sql

2)、alter table 數據庫表 add index 索引名稱(數據庫表字段名稱)數據庫

 

2、索引類型:性能優化

1)、PRIMARY KEY(主鍵索引) 數據結構

ALTER TABLE table_name ADD PRIMARY KEY ( column )函數

 

2)、UNIQUE(惟一索引) 性能

ALTER TABLE table_name ADD UNIQUE (column)大數據

 

3)、INDEX(普通索引) 優化

ALTER TABLE table_name ADD INDEX index_name ( column )

 

4)、FULLTEXT(全文索引)

ALTER TABLE table_name ADD FULLTEXT ( column )

 

5)、多列索引

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

 

3、操做

1).普通索引。

這是最基本的索引,它沒有任何限制。它有如下幾種建立方式:

 

1)建立索引:

CREATE INDEX indexName ON tableName(tableColumns(length));

若是是CHAR,VARCHAR類型,length能夠小於字段實際長度;若是是BLOB TEXT 類型,必須指定length,下同。

2)修改表結構:

ALTER tableName ADD INDEX [indexName] ON (tableColumns(length))

3)建立表的時候直接指定:

CREATE TABLE tableName ( [], INDEX [indexName] (tableColumns(length)) ;

 

2).惟一索引。

它與前面的」普通索引」相似,不一樣的就是:索引列的值必須惟一,但容許有空值。若是是組合索引,則列值的組合必須惟一。它有如下幾種建立方式:

 

1)建立索引:

CREATE UNIQUE INDEX indexName ON tableName(tableColumns(length))

2)修改表結構:

ALTER tableName ADD UNIQUE [indexName] ON (tableColumns(length))

3)建立表的時候直接指定:

CREATE TABLE tableName ( [], UNIQUE [indexName] (tableColumns(length));

 

3).主鍵索引

它是一種特殊的惟一索引,不容許有空值。通常是在建表的時候同時建立主鍵索引:

 

CREATE TABLE testIndex(i_testID INT NOT NULL AUTO_INCREMENT,vc_Name VARCHAR(16) NOT NULL,PRIMARY KEY(i_testID)); 固然也能夠用ALTER命令。

 

 

B、索引的原理及案例

 

 

主鍵是邏輯鍵,索引是物理鍵,意思就是主鍵不實際存在,而索引實際存在在數據庫中

索引會真正的產生一個文件的,數據會真正的產生一個文件的

redo log 記錄的是物理日誌"某個數據頁上作了什麼修改循環使用

bin log 記錄的是邏輯日誌 語句的原始邏輯"ID=1 ,2 " 追加使用

而主鍵不會產生一個文件的 主鍵的搜索靠索引的樹的搜索

 

 

數據的概念

數據有數據頁的概念

mysql也有內存的概念 ,查詢的時候 先看所在的數據頁 是否在內存中 ,若是存在查詢直接返回,若是不存在則去磁盤加載到內存再返回

因此更新操做

若是內存不存在 先去磁盤加載到內存而後修改後 再將值放入內存 ,而且再更新到redo log 日誌表中

索引的原理

1.B+樹索引 二叉搜索樹這棵樹是平衡二叉樹 N叉樹爲了減小樹高

若是語句是 select * from T where ID=500,即主鍵查詢方式,則只須要搜索 ID 這棵 B+

若是語句是 select * from T where k=5,即普通索引查詢方式,則須要先搜索 k 索引樹,ID 的值爲 500,再到 ID 索引樹搜索一次。這個過程稱回表

也就是說,基於非主鍵索引的查詢須要多掃描一棵索引樹,所以,咱們在應用中應該儘可能使用主鍵查詢。

2. 一個數據頁滿了,按照B+Tree算法,新增長一個數據頁,叫作頁分裂,會致使性能降低。空間利用率下降大概50%

當相鄰的兩個數據頁利用率很低的時候會作數據頁合併,合併的過程是分裂過程的逆過程。

3.從性能和存儲空間方面考量,自增主鍵每每是更合理的選擇。

4.顯然,主鍵長度越小,普通索引的葉子節點就越小,普通索引佔用的空間也就越小。

所以自增主鍵比較合適

 

覆蓋索引

create table T ( ID int primary key,

k int NOT NULL DEFAULT 0,

s varchar(16) NOT NULL DEFAULT '',

index k(k))

engine=InnoDB;

insert into T values(100,1, 'aa'),(200,2,'bb'),(300,3,'cc'),(500,5,'ee'),(600,6,'ff'),(700,7,'gg');

select * from T where k between 3 and 5  這種查詢K的索引搜索到主鍵 而後搜索主鍵的索引 拿到具體的信息有回表

覆蓋索引

select ID from T where k between 3 and 5 這時只須要查 ID 的值,而 ID 的值已經在 k 索引樹上了,所以能夠直接提供查詢結果,不須要回表 因爲覆蓋索引能夠減小樹的搜索次數,顯著提高查詢性能,因此使用覆蓋索引是一個經常使用的性能優化手段。

 

最左前綴原則

索引(a,b) 查詢條件b是沒法使用聯合索引的 查詢條件a可使用索引

%%開頭是不會使用索引的

 

修改索引刪除記錄

alter table T engine=InnoDB

 

關於索引的題

CREATE TABLE `geek` (

  `a` int(11) NOT NULL,

  `b` int(11) NOT NULL,

  `c` int(11) NOT NULL,

  `d` int(11) NOT NULL,

  PRIMARY KEY (`a`,`b`),

  KEY `c` (`c`),

  KEY `ca` (`c`,`a`),

  KEY `cb` (`c`,`b`)

) ENGINE=InnoDB;

因爲歷史緣由,這個表須要 ab 作聯合主鍵

那意味着單獨在字段 c 上建立一個索引,就已經包含了三個字段爲何要建立「ca」「cb」這兩個索引?

select * from geek where c=N order by a limit 1;//c的索引同樣

select * from geek where c=N order by b limit 1;//c的索引不同

問題 這位同事的解釋對嗎? 哪些索引沒有必要能夠刪除

 

表記錄

a--|b--|c--|d--

1 2 3 d

1 3 2 d

1 4 3 d

2 1 3 d

2 2 2 d

2 3 4 d

主鍵 ab 的聚簇索引組織順序至關於 order by a,b ,也就是先按 a 排序,再按 b 排序,c 無序。

索引 ca 的組織是先按 c 排序,再按 a 排序,同時記錄主鍵

c--|a--|–主鍵部分b-- (注意,這裏不是 ab,而是隻有 b

2 1 3

2 2 2

3 1 2

3 1 4

3 2 1

4 2 3

上面的這個索引ca 與 索引c 的數據是如出一轍的

 

索引 cb 的組織是先按 c 排序,在按 b 排序,同時記錄主鍵

c--|b--|–主鍵部分a-- (同上)

2 2 2

2 3 1

3 1 2

3 2 1

3 4 1

4 3 2

 

因此結論是ca能夠去掉 cb保留

 

 

經常使用的兩種索引結構:B-treeHASH

B-tree

  B-tree索引可以加快訪問數據的速度,由於存儲引擎再也不須要經行全表掃描來獲取須要的數據,取而代之的是從根節點開始搜索。根節點的槽中存放了指向子節點的指針,存儲引擎根據這些指針向下查找。一般比較節點頁的值和要查找的值能夠找到合適的指針進入下層子節點。

B-tree一般意味着全部的值都是按順序存儲的,而且每個葉子頁到根的距離相同。
  如上圖,是一顆B-tree,關於B-tree的定義能夠參見B-tree,這裏只說一些重點,淺藍色的塊咱們稱之爲一個磁盤塊,能夠看到每一個磁盤塊包含幾個數據項(深藍色所示)指針(黃色所示),如磁盤塊1包含數據項17和35,包含指針P一、P二、P3,P1表示小於17的磁盤塊P2表示在17和35之間的磁盤塊P3表示大於35的磁盤塊。真實的數據存在於葉子節點即三、五、九、十、1三、1五、2八、2九、3六、60、7五、7九、90、99。非葉子節點只不存儲真實的數據,只存儲指引搜索方向的數據項,如1七、35並不真實存在於數據表中。

B-tree的查找過程

  如圖所示,若是要查找數據項29,那麼首先會把磁盤塊1由磁盤加載到內存,此時發生一次IO,在內存中用二分查找肯定29在17和35之間,鎖定磁盤塊1的P2指針,內存時間由於很是短(相比磁盤的IO)能夠忽略不計,經過磁盤塊1的P2指針的磁盤地址磁盤塊3由磁盤加載到內存,發生第二次IO29在26和30之間,鎖定磁盤塊3P2指針,經過指針加載磁盤塊8到內存,發生第三次IO,同時內存中作二分查找找到29,結束查詢,總計三次IO。真實的狀況是,3層的B-tree能夠表示上百萬的數據,若是上百萬的數據查找只須要三次IO,性能提升將是巨大的,若是沒有索引,每一個數據項都要發生一次IO,那麼總共須要百萬次的IO,顯然成本很是很是高。

B-tree性質

  1. 經過上面的分析,咱們知道IO次數取決於b+數的高度h,假設當前數據表的數據爲N,每一個磁盤塊的數據項的數量是m,則有h=㏒(m+1) N,當數據量N必定的狀況下,m越大,h越小;而m = 磁盤塊的大小 / 數據項的大小,磁盤塊的大小也就是一個數據頁的大小,是固定的,若是數據項佔的空間越小,數據項的數量越多,樹的高度越低。這就是爲何每一個數據項,即索引字段要儘可能的小,好比int佔4字節,要比bigint8字節少一半。這也是爲何B-tree要求把真實的數據放到葉子節點而不是內層節點,一旦放到內層節點,磁盤塊的數據項會大幅度降低,致使樹增高。當數據項等於1時將會退化成線性表。
  2. B-tree的數據項是複合的數據結構,好比(name,age,sex)的時候,b+數是按照從左到右的順序來創建搜索樹的,好比當(張三,20,F)這樣的數據來檢索的時候,B-tree會優先比較name來肯定下一步的所搜方向,若是name相同再依次比較age和sex,最後獲得檢索的數據;但當(20,F)這樣的沒有name的數據來的時候,B-tree就不知道下一步該查哪一個節點,由於創建搜索樹的時候name就是第一個比較因子,必需要先根據name來搜索才能知道下一步去哪裏查詢。好比當(張三,F)這樣的數據來檢索時,B-tree能夠用name來指定搜索方向,但下一個字段age的缺失,因此只能把名字等於張三的數據都找到,而後再匹配性別是F的數據了, 這個是很是重要的性質,即索引的最左匹配特性。

注意:B-tree的高度通常都在2-4層,這也就是說查找某一鍵值的行記錄最多隻要2到4次IO,花費0.02-0.04秒左右。B-tree索引適用於全值匹配匹配最左前綴匹配列前綴匹配範圍值

創建索引的原則

  1. 最左前綴匹配原則,很是重要的原則,mysql會一直向右匹配直到遇到範圍查詢(>、<、between、like)就中止匹配,好比a = 1 and b = 2 and c > 3 and d = 4 若是創建(a,b,c,d)順序的索引,d是用不到索引的,若是創建(a,b,d,c)的索引則均可以用到,a,b,d的順序能夠任意調整。
  2. =和in能夠亂序,好比a = 1 and b = 2and c = 3 創建(a,b,c)索引能夠任意順序,mysql的查詢優化器會幫你優化成索引能夠識別的形式。
  3. 儘可能選擇區分度高的列做爲索引,區分度的公式是count(distinct col)/count(*),表示字段不重複的比例,比例越大咱們掃描的記錄數越少,惟一鍵的區分度是1,而一些狀態、性別字段可能在大數據面前區分度就是0,那可能有人會問,這個比例有什麼經驗值嗎?使用場景不一樣,這個值也很難肯定,通常須要join的字段咱們都要求是0.1以上,即平均1條掃描10條記錄。
  4. 索引列不能參與計算,保持列「乾淨」,好比from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,緣由很簡單,b+樹中存的都是數據表中的字段值,但進行檢索時,須要把全部元素都應用函數才能比較,顯然成本太大。因此語句應該寫成create_time = unix_timestamp(’2014-05-29’);
  5. 儘可能的擴展索引,不要新建索引。好比表中已經有a的索引,如今要加(a,b)的索引,那麼只須要修改原來的索引便可。

舉例子:

數據表以下,

 

數據量:

 

咱們經過explain查看執行計劃
首先咱們在沒有添加索引時,進行以下查詢。咱們能夠看出type=all代表全表掃描,估計查詢行數爲4070行。

 

 

咱們經過explain查看執行計劃
首先咱們在沒有添加索引時,進行以下查詢。咱們能夠看出type=all代表全表掃描,估計查詢行數爲4070行。

 

如今咱們添加索引以下,

 

 

 

在經過explain查詢執行計劃,咱們發現該查詢的行數估計爲1行。

哈希索引

  Mysql中只有在memory引擎顯示支持哈希索引。
哈希索引基於哈希表實現,只有精確匹配索引全部列的列纔有效。 對於每一行數據,存儲引擎都會對全部索引計算一個哈希碼,哈希碼是一個較小的值而且不一樣鍵值計算出來的哈希碼都不同。哈希索引將全部的哈希碼存儲在索引中,同時在哈希表中保存指向每一個數據的指針

哈希索引的限制:

  • 哈希索引只包含哈希值和行指針,而不知存儲字段值,因此不能使用索引中的值來避免讀取行ID也必須回表)。若讀取行,則必須進行行一次IO操做。
  • 哈希索引並非按照哈希值順序存儲的,因此也就沒法用於排序
  • 哈希值也不支持部分索引,由於哈希值始終是使用索引列中全部的內容計算哈希值的。例如,在數據(A,B)上創建哈希索引,若是隻查詢A則不能使用哈希索引。
  • 哈希索引只支持等值查詢
  • 哈希索引查詢速度很是快,除非出現出現衝突。

注意:Innodb引擎有一個特殊的功能叫作「自適應哈希索引」。當Innodb注意到某些索引值使用很是頻繁時,它會在內存中基於B-tree索引之上再創建一個哈希索引。這是一個徹底自動、內部的行爲,用戶沒法配置或者設置,不過有必要能夠關閉此功能

建立自定義哈希索引

思路:在B-tree基礎上建立一個僞哈希索引。這和真正的哈希索引不是一回事,它使用哈希值而不是鍵自己經行查找。須要在操做中在where語句中手動指定哈希函數。

 

其中,url_crc用來存儲哈希值。該值根據url和哈希函數得出。
咱們經過觸發器來實現維護哈希值

 

 

若是採用這種方式,記住不要使用SHA1()和MD5()做爲哈希函數。由於這兩個值計算出來的哈希值是很是長的字符串,會浪費大量時間,比較時也會比較慢。
在出現哈希衝突時,必須在子句中包含常量值。

 

 

 

 

 

 

 

 

 

 

 

Mysql常見的索引:主鍵索引、惟一索引、普通索引、全文索引、組合索引

1.惟一索引

與普通索引相似,不一樣的就是:索引列的值必須惟一,但容許有空值(注意和主鍵不一樣)。若是是組合索引,則列值的組合必須惟一

例如,在已經存好數據的表中添加惟一索引,若是值有重複會報錯,

2.主鍵索引

它是一種特殊的惟一索引,不容許有空值。

3.組合索引

平時用的SQL查詢語句通常都有比較多的限制條件,因此爲了進一步榨取MySQL的效率,就要考慮創建組合索引。

至關於同時建立了三個索引,
ConutryCode,District,Name),(CountryCode,District),(CountryCode)。
這是由於從最左開始組合的。因此依次生成了三個索引。

3.全文索引

  在前面描述中,在B-tree中能夠經過列前綴進行查詢。例如

select * from testwhere body=」hello%」;

然而,咱們更廣泛的查找方式是,

select * from testwhere body=」%hello%」;

全文索引能夠支持各類字符在內的搜索,也支持天然語言搜索和布爾搜索

注意,在innodb存儲引擎中爲了支持全文索引,必須有一列與word經行映射。Innodb中這個列別命名爲FTS_DOC_ID,其類型必須是BIGINT UNSIGNED NOT NULL,而且innodb存儲引擎自動會在該列上加入一個名爲FTS_DOC_ID_INDEX的unique index。上述操做都是由Innodb存儲引擎本身完成的,用戶也可在建表時手動添加FTS_DOC_ID以及相應的Unique idnex。

  1. 插入數據

 

  1. 創建全文索引

mysql> create fulltext index idx on fts(body);

能夠看出每個word都對應一個DOC_ID和POSITION。此外還記錄了FIRST_ID,LAST_DOC_ID以及DOC_COUNT,分別表明了word第一次出現的文檔ID,最後一次出現的文檔ID,以及word在在多少個文檔中存在。

全文索引的天然語言索引

天然語言索引引擎將計算每個文檔對象和查詢的相關度。這裏,相關度是指基於匹配的關鍵詞個數,以及關鍵詞在文檔中出現的個數。
天然語言索引是默認的。
函數match()將返回關鍵詞匹配的相關度,是一個浮點數字。
match()中指定的列必須和全文索引中指定的列徹底相同,不然沒法只用全文索引。
舉例子,

 

Boolen全文索引

Mysql數據庫容許使用in boolen model修飾符來經行全文檢索。當使用該修飾符時,查詢字符串先後字符會有特殊含義。

Boolen全文檢索支持如下幾種操做符:
l +:表示word必須存在
l -:表示word必須不存在

l (no operator) 表示word是可選的。可是若是是可選的,其相關性會更高。

 

 

l @distance表示查詢的多個單詞之間的距離是否在distance以內。

 

2 rows in set(0.00 sec)
l >表示出現該word增長相關性
l <表示出現該word下降相關性

l ~容許出現該單詞,可是出現時相關性爲負。
表示以該單詞開頭的單詞,如lik,表示能夠是like,likes和lik

---------------+2 rows in set(0.00 sec)

 

 

l 「表示短語

注意到,第一個against(「hello world「)是將hello和world看成兩個單詞經行查詢。而第二個against(‘」hello world「’)是將這兩個單詞看成短語經行查詢。

索引區別

普通索引:最基本的索引,沒有任何限制
惟一索引:與"普通索引"相似,不一樣的就是:索引列的值必須惟一,但容許有空值。
主鍵索引:它是一種特殊的惟一索引,不容許有空值。
全文索引:針對較大的數據,生成全文索引很耗時好空間。
組合索引:爲了更多的提升mysql效率可創建組合索引,遵循」最左前綴「原則。

相關文章
相關標籤/搜索