溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

MySQL數(shù)據(jù)庫索引的介紹

發(fā)布時間:2020-05-27 22:19:13 來源:億速云 閱讀:257 作者:鴿子 欄目:編程語言

一、MySQL有哪些索引類型

索引的分類可以從多個角度進(jìn)行,下面分別從數(shù)據(jù)結(jié)構(gòu),物理存儲和業(yè)務(wù)邏輯三個維度進(jìn)行劃分。

1、從數(shù)據(jù)結(jié)構(gòu)角度

(1)B+樹索引(O(log(n)))

關(guān)于B+樹索引,后面會深入解析

(2)hash索引
  • 僅僅能滿足"=","IN"和"<=>"查詢,不能使用范圍查詢
  • 其檢索效率非常高,索引的檢索可以一次定位,不像B-Tree 索引需要從根節(jié)點(diǎn)到枝節(jié)點(diǎn),最后才能訪問到頁節(jié)點(diǎn)這樣多次的IO訪問,所以 Hash 索引的查詢效率要遠(yuǎn)高于 B-Tree 索引
  • 只有Memory存儲引擎顯示支持hash索引
(3)FULLTEXT索引

現(xiàn)在MyISAM和InnoDB引擎都支持了

(4)R-Tree索引

用于對GIS數(shù)據(jù)類型創(chuàng)建SPATIAL索引

2、從物理存儲角度

(1)聚集索引(clustered index)
  • 正文內(nèi)容按照一個特定維度排序存儲,這個特定的維度就是聚集索引;
  • Innodb存儲引擎中行記錄就是按照聚集索引維度順序存儲的,Innodb的表也稱為索引表;因為行記錄只能按照一個維度進(jìn)行排序,所以一張表只能有一個聚集索引。
(2)非聚集索引(non-clustered index)
  • 索引是通過二叉樹的數(shù)據(jù)結(jié)構(gòu)來描述的,我們可以這么理解聚簇索引:索引的葉節(jié)點(diǎn)就是數(shù)據(jù)節(jié)點(diǎn)。而非聚簇索引的葉節(jié)點(diǎn)仍然是索引節(jié)點(diǎn),只不過有一個指針指向?qū)?yīng)的數(shù)據(jù)塊。

  • 非聚集索引索引項順序存儲,但索引項對應(yīng)的內(nèi)容卻是隨機(jī)存儲的;

舉個例子說明下:

create table student (
`id` INT UNSIGNED AUTO_INCREMENT,
`name` VARCHAR(255),
PRIMARY KEY(`id`),
KEY(`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

該表中主鍵id是該表的聚集索引、name為非聚集索引;表中的每行數(shù)據(jù)都是按照聚集索引id排序存儲的;比如要查找name='Arla'和name='Arle'的兩個同學(xué),他們在name索引表中位置可能是相鄰的,但是實(shí)際存儲位置可能差的很遠(yuǎn)。name索引表節(jié)點(diǎn)按照name排序,檢索的是每一行數(shù)據(jù)的主鍵。聚集索引表按照主鍵id排序,檢索的是每一行數(shù)據(jù)的真實(shí)內(nèi)容。

3、從邏輯角度

(1)主鍵索引

主鍵索引是一種特殊的唯一索引,不允許有空值

(2)普通索引或者單列索引
(3)多列索引(復(fù)合索引)

復(fù)合索引指多個字段上創(chuàng)建的索引,只有在查詢條件中使用了創(chuàng)建索引時的第一個字段,索引才會被使用。使用復(fù)合索引時遵循最左前綴集合

(4)唯一索引或者非唯一索引
(5)空間索引

空間索引是對空間數(shù)據(jù)類型的字段建立的索引,MYSQL中的空間數(shù)據(jù)類型有4種,分別是GEOMETRY、POINT、LINESTRING、POLYGON。

MYSQL使用SPATIAL關(guān)鍵字進(jìn)行擴(kuò)展,使得能夠用于創(chuàng)建正規(guī)索引類型的語法創(chuàng)建空間索引。創(chuàng)建空間索引的列,必須將其聲明為NOT NULL,空間索引只能在存儲引擎為MYISAM的表中創(chuàng)建.

二、索引創(chuàng)建方式

CREATE TABLE table_name[col_name data type]
[unique|fulltext|spatial][index|key][index_name](col_name[length])[asc|desc]
  • unique|fulltext|spatial為可選參數(shù),分別表示唯一索引、全文索引和空間索引;
  • index和key為同義詞,兩者作用相同,用來指定創(chuàng)建索引
  • col_name為需要創(chuàng)建索引的字段列,該列必須從數(shù)據(jù)表中該定義的多個列中選擇;
  • index_name指定索引的名稱,為可選參數(shù),如果不指定,MYSQL默認(rèn)col_name為索引值;length為可選參數(shù),表示索引的長度,只有字符串類型的字段才能指定索引長度;
  • asc或desc指定升序或降序的索引值存儲

1、創(chuàng)建表時建立索引

(1)創(chuàng)建普通索引
create table table_name(
    id int(11),
    name varchar(20),
    sex boolean,
    INDEX(id)
);

查看表結(jié)構(gòu)

show create table table_name;
可以使 EXPLAIN 語句查看索引是否被使用

explain select * from table_name where id = 1\G
(2)創(chuàng)建唯一索引
create table index2(
    id int unique,
    name varchar(20),
    unique INDEX index_2(id asc)
);
(3)創(chuàng)建全文索引

全文索引只能在char,varchar或者text 類型的字段上。而且,只有MyISAM 儲存引擎支持全文索引。

create table idnex3(
    id int,
    info varchar(20),
    FULLTEXT INDEX index3_info(info)
)ENGINE=MyISAM;
(4)創(chuàng)建單列索引
create table index4(
    id int,
    subject varchar(255),
    index index4_st(subject(10))
);

這里需要注意的,subject 的長度為255,但是index4_st索引只有10。這樣做的目的還是為了提高查詢速度。對于字符型的數(shù)據(jù),可以不用查詢?nèi)啃畔?,只查詢其前面的若干字符信息?/p>

(5)創(chuàng)建多列索引
create table index5(
    id int,
    name varchar(20),
    sex char(4),
    index index5_ns(name.sex)
);

這是我們可以看到,name 和sex字段上已經(jīng)創(chuàng)建了index_ns索引。

2、在已經(jīng)存在的表中創(chuàng)建索引

(1)創(chuàng)建普通索引

在example0() 表中的id 創(chuàng)建名為index7_id 的索引。

create index index7_id on example0(id);
(2)創(chuàng)建唯一索引
create UNIQUE index index_name on table_name(name);
(3)創(chuàng)建全文索引
create FULLTEXT index index_name on table_name(info);
(4)創(chuàng)建單列索引
create INDEX index_name ON table_name(name(10));
(5)創(chuàng)建多列索引
create INDEX index_name ON table_name(name,sex);

3、用alter table 語句來創(chuàng)建索引

(1)創(chuàng)建普通索引

在name字段上創(chuàng)建名為indx_name 的索引

alter table table_name ADD INDEX index_name(name(20));
(2)創(chuàng)建唯一性索引
alter table table_name ADD UNIQUE INDEX index_name(id);
(3)創(chuàng)建全文索引
alter table table_name ADD FULLTEXT INDEX index_name(info);
(4)創(chuàng)建單列索引
alter table table_name ADD INDEX index_name(name(4));
(5)創(chuàng)建多列索引
alter tabel table_name ADD INDEX index_name(name.sex);

4、刪除索引

DROP INDEX index_name ON table_name;

三、索引樹是如何維護(hù)的

目前大部分?jǐn)?shù)據(jù)庫系統(tǒng)及文件系統(tǒng)都采用B-Tree或其變種B+Tree作為索引結(jié)構(gòu),那么索引樹是如何維護(hù)的?

1、查找結(jié)構(gòu)進(jìn)化史

查找是數(shù)據(jù)結(jié)構(gòu)和算法中一個非常重要的概念。

  • 線性查找:一個個找;實(shí)現(xiàn)簡單;太慢
  • 二分查找:有序;簡單;要求是有序的,插入特別慢
  • HASH查找:查詢快;占用空間;不太適合存儲大規(guī)模數(shù)據(jù)
  • 二叉查找樹:插入和查詢很快(log(n));無法存大規(guī)模數(shù)據(jù),復(fù)雜度退化
  • 平衡樹:解決 BST 退化問題,樹是平衡的;節(jié)點(diǎn)非常多的時候,依然樹高很高
  • 多路查找樹:一個父親多個孩子節(jié)點(diǎn)(度);節(jié)點(diǎn)過多樹高不會特別深
  • 多路平衡查找樹:B-Tree

2、B-Tree

B-Tree是一種多路搜索樹(并不是二叉的):

  1. 定義任意非葉子結(jié)點(diǎn)最多只有M個兒子;且M>2;
  2. 根結(jié)點(diǎn)的兒子數(shù)為[2, M];
  3. 除根結(jié)點(diǎn)以外的非葉子結(jié)點(diǎn)的兒子數(shù)為[M/2, M];
  4. 每個結(jié)點(diǎn)存放至少M(fèi)/2-1(取上整)和至多M-1個關(guān)鍵字;(至少2個關(guān)鍵字)
  5. 非葉子結(jié)點(diǎn)的關(guān)鍵字個數(shù)=指向兒子的指針個數(shù)-1;
  6. 非葉子結(jié)點(diǎn)的關(guān)鍵字:K[1], K[2], …, K[M-1];且K[i] < K[i+1];
  7. 非葉子結(jié)點(diǎn)的指針:P[1], P[2], …, P[M];其中P[1]指向關(guān)鍵字小于K[1]的
    子樹,P[M]指向關(guān)鍵字大于K[M-1]的子樹,其它P[i]指向關(guān)鍵字屬于(K[i-1], K[i])的子樹;
  8. 所有葉子結(jié)點(diǎn)位于同一層;
  9. 每個k對應(yīng)一個data。
    如:(M=3)相當(dāng)于一個2–3樹,2–3樹是一個這樣的一棵樹, 它的每個節(jié)點(diǎn)要么有2個孩子和1個數(shù)據(jù)元素,要么有3個孩子和2個數(shù)據(jù)元素,葉子節(jié)點(diǎn)沒有孩子,并且有1個或2個數(shù)據(jù)元素。

MySQL數(shù)據(jù)庫索引的介紹

B-樹的搜索,從根結(jié)點(diǎn)開始,對結(jié)點(diǎn)內(nèi)的關(guān)鍵字(有序)序列進(jìn)行二分查找,如果命中則結(jié)束,否則進(jìn)入查詢關(guān)鍵字所屬范圍的兒子結(jié)點(diǎn);重復(fù),直到所對應(yīng)的兒子指針為空,或已經(jīng)是葉子結(jié)點(diǎn);B-Tree上查找算法的偽代碼如下:

BTree_Search(node, key) { if(node == null) return null; foreach(node.key) { if(node.key[i] == key) return node.data[i]; if(node.key[i] > key) return BTree_Search(point[i]->node); } return BTree_Search(point[i+1]->node); } data = BTree_Search(root, my_key);
(1)B-樹的特性
  1. 關(guān)鍵字集合分布在整顆樹中;
  2. 任何一個關(guān)鍵字出現(xiàn)且只出現(xiàn)在一個結(jié)點(diǎn)中;
  3. 搜索有可能在非葉子結(jié)點(diǎn)結(jié)束;
  4. 其搜索性能等價于在關(guān)鍵字全集內(nèi)做一次二分查找;
  5. 自動層次控制;
(2)B-樹的自控制

B樹中每一個內(nèi)部節(jié)點(diǎn)會包含一定數(shù)量的鍵值。通常,鍵值的數(shù)量被選定在d和2d之間。在實(shí)際中,鍵值占用了節(jié)點(diǎn)中大部分的空間。因數(shù)2將保證節(jié)點(diǎn)可以被拆分或組合。如果一個內(nèi)部節(jié)點(diǎn)有2d個鍵值,那么添加一個鍵值給此節(jié)點(diǎn)的過程,將會拆分2d鍵值為2個d鍵值的節(jié)點(diǎn),并把此鍵值添加給父節(jié)點(diǎn)。每一個拆分的節(jié)點(diǎn)需要最小數(shù)目的鍵值。相似地,如果一個內(nèi)部節(jié)點(diǎn)和他的鄰居兩者都有d個鍵值,那么將通過它與鄰居的合并來刪除一個鍵值。刪除此鍵值將導(dǎo)致此節(jié)點(diǎn)擁有d-1個鍵值;與鄰居的合并則加上d個鍵值,再加上從鄰居節(jié)點(diǎn)的父節(jié)點(diǎn)移來的一個鍵值。結(jié)果為完全填充的2d個鍵值。

(3)B-樹的構(gòu)造過程

下面是往B樹中依次插入

6 10 4 14 5 11 15 3 2 12 1 7 8 8 6 3 6 21 5 15 15 6 32 23 45 65 7 8 6 5 4

MySQL數(shù)據(jù)庫索引的介紹

3、B+Tree

B-Tree有許多變種,其中最常見的是B+Tree,MySQL就普遍使用B+Tree實(shí)現(xiàn)其索引結(jié)構(gòu)。
與B-Tree相比,B+Tree有以下不同點(diǎn):

  1. 非葉子結(jié)點(diǎn)的子樹指針與關(guān)鍵字個數(shù)相同;
  2. 非葉子結(jié)點(diǎn)的子樹指針P[i],指向關(guān)鍵字值屬于[K[i], K[i+1])的子樹(B-樹是開區(qū)間);
  3. 為所有葉子結(jié)點(diǎn)增加一個鏈指針;
  4. 所有關(guān)鍵字都在葉子結(jié)點(diǎn)出現(xiàn);
  5. 內(nèi)節(jié)點(diǎn)不存儲data,只存儲key
    如:(M=3)

MySQL數(shù)據(jù)庫索引的介紹

B+的搜索與B-樹也基本相同,區(qū)別是B+樹只有達(dá)到葉子結(jié)點(diǎn)才命中(B-樹可以在非葉子結(jié)點(diǎn)命中),其性能也等價于在關(guān)鍵字全集做一次二分查找;

(1)B+的特性
  1. 所有關(guān)鍵字都出現(xiàn)在葉子結(jié)點(diǎn)的鏈表中(稠密索引),且鏈表中的關(guān)鍵字恰好是有序的;
  2. 不可能在非葉子結(jié)點(diǎn)命中;
  3. 非葉子結(jié)點(diǎn)相當(dāng)于是葉子結(jié)點(diǎn)的索引(稀疏索引),葉子結(jié)點(diǎn)相當(dāng)于是存儲(關(guān)鍵字)數(shù)據(jù)的數(shù)據(jù)層;
  4. 更適合文件索引系統(tǒng);
(2)B+樹的構(gòu)造過程

下面是往B+樹中依次插入

6 10 4 14 5 11 15 3 2 12 1 7 8 8 6 3 6 21 5 15 15 6 32 23 45 65 7 8 6 5 4

MySQL數(shù)據(jù)庫索引的介紹

3、索引的物理存儲

一般來說,索引本身也很大,不可能全部存儲在內(nèi)存中,因此索引往往以索引文件的形式存儲的磁盤上。

這樣的話,索引查找過程中就要產(chǎn)生磁盤I/O消耗,相對于內(nèi)存存取,I/O存取的消耗要高幾個數(shù)量級,所以評價一個數(shù)據(jù)結(jié)構(gòu)作為索引的優(yōu)劣最重要的指標(biāo)就是在查找過程中磁盤I/O操作次數(shù)的漸進(jìn)復(fù)雜度。換句話說,索引的結(jié)構(gòu)組織要盡量減少查找過程中磁盤I/O的存取次數(shù)。

假如每個盤塊可以正好存放一個B樹的結(jié)點(diǎn)(正好存放2個文件名)。那么一個BTNODE結(jié)點(diǎn)就代表一個盤塊,而子樹指針就是存放另外一個盤塊的地址。

(1)模擬B+樹查找過程

下面,咱們來模擬下查找文件29的過程:

MySQL數(shù)據(jù)庫索引的介紹

  1. 根據(jù)根結(jié)點(diǎn)指針找到文件目錄的根磁盤塊1,將其中的信息導(dǎo)入內(nèi)存?!敬疟PIO操作 1次】
  2. 此時內(nèi)存中有兩個文件名17、35和三個存儲其他磁盤頁面地址的數(shù)據(jù)。根據(jù)算法我們發(fā)現(xiàn):17<29<35,因此我們找到指針p2。
  3. 根據(jù)p2指針,我們定位到磁盤塊3,并將其中的信息導(dǎo)入內(nèi)存?!敬疟PIO操作 2次】
  4. 此時內(nèi)存中有兩個文件名26,30和三個存儲其他磁盤頁面地址的數(shù)據(jù)。根據(jù)算法我們發(fā)現(xiàn):26<29<30,因此我們找到指針p2。
  5. 根據(jù)p2指針,我們定位到磁盤塊8,并將其中的信息導(dǎo)入內(nèi)存?!敬疟PIO操作 3次】
  6. 此時內(nèi)存中有兩個文件名28,29。根據(jù)算法我們查找到文件名29,并定位了該文件內(nèi)存的磁盤地址。
    分析上面的過程,發(fā)現(xiàn)需要3次磁盤IO操作和3次內(nèi)存查找操作。關(guān)于內(nèi)存中的文件名查找,由于是一個有序表結(jié)構(gòu),可以利用折半查找提高效率。至于IO操作是影響整個B樹查找效率的決定因素。
    當(dāng)然,如果我們使用平衡二叉樹的磁盤存儲結(jié)構(gòu)來進(jìn)行查找,磁盤4次,最多5次,而且文件越多,B樹比平衡二叉樹所用的磁盤IO操作次數(shù)將越少,效率也越高。

4、B+tree的優(yōu)點(diǎn)

(1)B+-tree的磁盤讀寫代價更低

B+-tree的內(nèi)部結(jié)點(diǎn)并沒有指向關(guān)鍵字具體信息的指針。因此其內(nèi)部結(jié)點(diǎn)相對B 樹更小。如果把所有同一內(nèi)部結(jié)點(diǎn)的關(guān)鍵字存放在同一盤塊中,那么盤塊所能容納的關(guān)鍵字?jǐn)?shù)量也越多。一次性讀入內(nèi)存中的需要查找的關(guān)鍵字也就越多。相對來說IO讀寫次數(shù)也就降低了。
舉個例子,假設(shè)磁盤中的一個盤塊容納16bytes,而一個關(guān)鍵字2bytes,一個關(guān)鍵字具體信息指針2bytes。一棵9階B-tree(一個結(jié)點(diǎn)最多8個關(guān)鍵字)的內(nèi)部結(jié)點(diǎn)需要2個盤快。而B+
樹內(nèi)部結(jié)點(diǎn)只需要1個盤快。當(dāng)需要把內(nèi)部結(jié)點(diǎn)讀入內(nèi)存中的時候,B 樹就比B+樹多一次盤塊查找時間(在磁盤中就是盤片旋轉(zhuǎn)的時間)。

(2)B+-tree的查詢效率更加穩(wěn)定

由于非終結(jié)點(diǎn)并不是最終指向文件內(nèi)容的結(jié)點(diǎn),而只是葉子結(jié)點(diǎn)中關(guān)鍵字的索引。所以任何關(guān)鍵字的查找必須走一條從根結(jié)點(diǎn)到葉子結(jié)點(diǎn)的路。所有關(guān)鍵字查詢的路徑長度相同,導(dǎo)致每一個數(shù)據(jù)的查詢效率相當(dāng)。

四、索引創(chuàng)建有哪些原則

索引查詢是數(shù)據(jù)庫中重要的記錄查詢方法,要不要進(jìn)入索引以及在那些字段上建立索引都要和實(shí)際數(shù)據(jù)庫系統(tǒng)的查詢要求結(jié)合來考慮,下面給出實(shí)際中的一些通用的原則:

  1. 在經(jīng)常用作過濾器的字段上建立索引;
  2. 在SQL語句中經(jīng)常進(jìn)行GROUP BY、ORDER BY的字段上建立索引;
  3. 在不同值較少的字段上不必要建立索引,如性別字段;
  4. 對于經(jīng)常存取的列避免建立索引;
  5. 用于聯(lián)接的列(主健/外?。┥辖⑺饕?/li>
  6. 在經(jīng)常存取的多個列上建立復(fù)合索引,但要注意復(fù)合索引的建立順序要按照使用的頻度來確定;
  7. 缺省情況下建立的是非簇集索引,但在以下情況下最好考慮簇集索引,如:含有有限數(shù)目(不是很少)唯一的列;進(jìn)行大范圍的查詢;充分的利用索引可以減少表掃描I/0的次數(shù),有效的避免對整表的搜索。
  8. 經(jīng)常用在WHERE子句中的數(shù)據(jù)列;
  9. 經(jīng)常出現(xiàn)在關(guān)鍵字order by、group by、distinct后面的字段,建立索引。如果建立的是復(fù)合索引,索引的字段順序要和這些關(guān)鍵字后面的字段順序一致,否則索引不會被使用;
  10. 對于那些查詢中很少涉及的列,重復(fù)值比較多的列不要建立索引;
  11. 對于定義為text、image和bit的數(shù)據(jù)類型的列不要建立索引;
  12. 對于經(jīng)常存取的列避免建立索引;
  13. 限制表上的索引數(shù)目。對一個存在大量更新操作的表,所建索引的數(shù)目一般不要超過3個,最多不要超過5個。索引雖說提高了訪問速度,但太多索引會影響數(shù)據(jù)的更新操作。
  14. 對復(fù)合索引,按照字段在查詢條件中出現(xiàn)的頻度建立索引。在復(fù)合索引中,記錄首先按照第一個字段排序。對于在第一個字段上取值相同的記錄,系統(tǒng)再按照第二個字段的取值排序,以此類推。因此只有復(fù)合索引的第一個字段出現(xiàn)在查詢條件中,該索引才可能被使用,因此將應(yīng)用頻度高的字段,放置在復(fù)合索引的前面,會使系統(tǒng)最大可能地使用此索引,發(fā)揮索引的作用。

1、組合多個索引

一個單獨(dú)的索引掃描只能用于這樣的條件子句:使用被索引字段和索引操作符類中的操作符, 并且這些條件以AND連接。

假設(shè)在(a, b)上有一個索引, 那么類似WHERE a = 5 AND b = 6的條件可以使用索引,但是像WHERE a = 5 OR b = 6的條件就不能直接使用索引。

一個類似WHERE x =42 OR x = 47 OR x = 53 OR x = 99 這樣的查詢可以分解成四個在x上的獨(dú)立掃描,每個掃描使用一個條件, 最后將這些掃描的結(jié)果OR 在一起,生成最終結(jié)果。

另外一個例子是,如果我們在x 和y上有獨(dú)立的索引,一個類似WHERE x = 5 AND y = 6 這樣的查詢可以分解為幾個使用獨(dú)立索引的子句,然后把這幾個結(jié)果AND 在一起,生成最終結(jié)果。

五、索引失效有哪幾種情況

  1. 如果條件中有or,即使其中有條件帶索引也不會使用(這也是為什么盡量少用or的原因)
  2. 對于多列索引,不是使用的第一部分(第一個),則不會使用索引
  3. like查詢是以%開頭
  4. 如果列類型是字符串,那一定要在條件中將數(shù)據(jù)使用引號引用起來,否則不使用索引
  5. 如果mysql估計使用全表掃描要比使用索引快,則不使用索引

1、聯(lián)合索引失效的條件

聯(lián)合索引又叫復(fù)合索引。兩個或更多個列上的索引被稱作復(fù)合索引。

對于復(fù)合索引:Mysql從左到右的使用索引中的字段,一個查詢可以只使用索引中的一部份,但只能是最左側(cè)部分。例如索引是key index (a,b,c)。 可以支持a | a,b| a,b,c 3種組合進(jìn)行查找,但不支持 b,c進(jìn)行查找 .當(dāng)最左側(cè)字段是常量引用時,索引就十分有效。

所以說創(chuàng)建復(fù)合索引時,應(yīng)該仔細(xì)考慮列的順序。對索引中的所有列執(zhí)行搜索或僅對前幾列執(zhí)行搜索時,復(fù)合索引非常有用;僅對后面的任意列執(zhí)行搜索時,復(fù)合索引則沒有用處。

六、如何查看索引的使用情況

這里記錄兩種方式,分別是

1、使用Handler_read查看索引的使用情況

show status like ‘Handler_read%';

大家可以注意:

  • handler_read_key:這個值越高越好,越高表示使用索引查詢到的次數(shù)
  • handler_read_rnd_next:這個值越高,說明查詢低效
+-----------------------+--------------+
| Variable_name         | Value        |
+-----------------------+--------------+
| Handler_read_first    | 153      |
| Handler_read_key      | 364   |
| Handler_read_next     | 425    |
| Handler_read_prev     | 598     |
| Handler_read_rnd      | 605     |
| Handler_read_rnd_next | 860571 |
+-----------------------+--------------+
6 rows in set (0.00 sec)
————————————————

分析這幾個值,我們可以查看當(dāng)前索引的使用情況:

  • Handler_read_first:索引中第一條被讀的次數(shù)。如果較高,它表示服務(wù)器正執(zhí)行大量全索引掃描;例如,SELECT col1 FROM foo,假定col1有索引(這個值越低越好)。
  • Handler_read_key:如果索引正在工作,這個值代表一個行被索引值讀的次數(shù),如果值越低,表示索引得到的性能改善不高,因為索引不經(jīng)常使用(這個值越高越好)。
  • Handler_read_next :按照鍵順序讀下一行的請求數(shù)。如果你用范圍約束或如果執(zhí)行索引掃描來查詢索引列,該值增加。
  • Handler_read_prev:按照鍵順序讀前一行的請求數(shù)。該讀方法主要用于優(yōu)化ORDER BY ... DESC。
  • Handler_read_rnd :根據(jù)固定位置讀一行的請求數(shù)。如果你正執(zhí)行大量查詢并需要對結(jié)果進(jìn)行排序該值較高。你可能使用了大量需要MySQL掃描整個表的查詢或你的連接沒有正確使用鍵。這個值較高,意味著運(yùn)行效率低,應(yīng)該建立索引來補(bǔ)救。
  • Handler_read_rnd_next:在數(shù)據(jù)文件中讀下一行的請求數(shù)。如果你正進(jìn)行大量的表掃描,該值較高。通常說明你的表索引不正確或?qū)懭氲牟樵儧]有利用索引。

2、在sys庫中查看沒用的索引

查詢 schema_unused_indexes庫。

root@localhost [sys]>select * from schema_unused_indexes;
+-------------------+-------------+------------+
| object_schema     | object_name | index_name |
+-------------------+-------------+------------+
| sysbench_testdata | sbtest1     | k_1        |
| sysbench_testdata | sbtest10    | k_10       |
| sysbench_testdata | sbtest3     | k_3        |
| sysbench_testdata | sbtest4     | k_4        |
| sysbench_testdata | sbtest5     | k_5        |
| sysbench_testdata | sbtest6     | k_6        |
| sysbench_testdata | sbtest7     | k_7        |
| sysbench_testdata | sbtest8     | k_8        |
| sysbench_testdata | sbtest9     | k_9        |
+-------------------+-------------+------------+
9 rows in set (0.00 sec)

七、EXPLAIN解釋命令查看索引是否生效

explain顯示了mysql如何使用索引來處理select語句以及連接表。可以幫助選擇更好的索引和寫出更優(yōu)化的查詢語句。

1、一個實(shí)際例子

新建一張表,

CREATE TABLE IF NOT EXISTS `article` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`author_id` int(10) unsigned NOT NULL,
`category_id` int(10) unsigned NOT NULL,
`views` int(10) unsigned NOT NULL,
`comments` int(10) unsigned NOT NULL,
`title` varbinary(255) NOT NULL,
`content` text NOT NULL,
PRIMARY KEY (`id`)
);

執(zhí)行查詢,

EXPLAIN
SELECT author_id
FROM `article`
WHERE category_id = 1 AND comments > 1
ORDER BY views DESC
LIMIT 1

響應(yīng)數(shù)據(jù)如下,

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: article
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 3
        Extra: Using where; Using filesort
1 row in set (0.00 sec)

type 是 ALL,即最壞的情況。Extra 里還出現(xiàn)了 Using filesort,也是最壞的情況。

2、EXPLAIN列的解釋:

  • table:顯示這一行的數(shù)據(jù)是關(guān)于哪張表的
  • type:這是重要的列,顯示連接使用了何種類型。從最好到最差的連接類型為const、eq_reg、ref、range、indexhe和ALL
  • possible_keys:顯示可能應(yīng)用在這張表中的索引。如果為空,沒有可能的索引??梢詾橄嚓P(guān)的域從WHERE語句中選擇一個合適的語句
  • key: 實(shí)際使用的索引。如果為NULL,則沒有使用索引。很少的情況下,MYSQL會選擇優(yōu)化不足的索引。這種情況下,可以在SELECT語句中使用USE INDEX(indexname)來強(qiáng)制使用一個索引或者用IGNORE INDEX(indexname)來強(qiáng)制MYSQL忽略索引
  • key_len:使用的索引的長度。在不損失精確性的情況下,長度越短越好
  • ref:顯示索引的哪一列被使用了,如果可能的話,是一個常數(shù)
  • rows:MYSQL認(rèn)為必須檢查的用來返回請求數(shù)據(jù)的行數(shù)
  • Extra:關(guān)于MYSQL如何解析查詢的額外信息。將在表4.3中討論,但這里可以看到的壞的例子是Using temporary和Using filesort,意思MYSQL根本不能使用索引,結(jié)果是檢索會很慢

3、type返回結(jié)果的解釋

MySQL 在表里找到所需行的方式。包括(由左至右,由最差到最好):
| All | index | range | ref | eq_ref | const,system | null |

  • system 表只有一行:system表。這是const連接類型的特殊情況
  • const:表中的一個記錄的最大值能夠匹配這個查詢(索引可以是主鍵或惟一索引)。因為只有一行,這個值實(shí)際就是常數(shù),因為MYSQL先讀這個值然后把它當(dāng)做常數(shù)來對待
  • eq_ref:在連接中,MYSQL在查詢時,從前面的表中,對每一個記錄的聯(lián)合都從表中讀取一個記錄,它在查詢使用了索引為主鍵或惟一鍵的全部時使用
  • ref:這個連接類型只有在查詢使用了不是惟一或主鍵的鍵或者是這些類型的部分(比如,利用最左邊前綴)時發(fā)生。對于之前的表的每一個行聯(lián)合,全部記錄都將從表中讀出。這個類型嚴(yán)重依賴于根據(jù)索引匹配的記錄多少—越少越好
  • range:這個連接類型使用索引返回一個范圍中的行,比如使用>或<查找東西時發(fā)生的情況
  • index: 這個連接類型對前面的表中的每一個記錄聯(lián)合進(jìn)行完全掃描(比ALL更好,因為索引一般小于表數(shù)據(jù))
  • ALL:這個連接類型對于前面的每一個記錄聯(lián)合進(jìn)行完全掃描,這一般比較糟糕,應(yīng)該盡量避免

4、extra列返回的描述的意義

  • Distinct:一旦MYSQL找到了與行相聯(lián)合匹配的行,就不再搜索了
  • Not exists: MYSQL優(yōu)化了LEFT JOIN,一旦它找到了匹配LEFT JOIN標(biāo)準(zhǔn)的行,就不再搜索了
  • Range checked for each Record(index map:#):沒有找到理想的索引,因此對于從前面表中來的每一個行組合,MYSQL檢查使用哪個索引,并用它來從表中返回行。這是使用索引的最慢的連接之一
  • Using filesort: 看到這個的時候,查詢就需要優(yōu)化了。MYSQL需要進(jìn)行額外的步驟來發(fā)現(xiàn)如何對返回的行排序。它根據(jù)連接類型以及存儲排序鍵值和匹配條件的全部行的行指針來排序全部行
  • Using index: 列數(shù)據(jù)是從僅僅使用了索引中的信息而沒有讀取實(shí)際的行動的表返回的,這發(fā)生在對表的全部的請求列都是同一個索引的部分的時候
  • Using temporary 看到這個的時候,查詢需要優(yōu)化了。這里,MYSQL需要創(chuàng)建一個臨時表來存儲結(jié)果,這通常發(fā)生在對不同的列集進(jìn)行ORDER BY上,而不是GROUP BY上
  • Using where 使用了WHERE從句來限制哪些行將與下一張表匹配或者是返回給用戶。如果不想返回表中的全部行,并且連接類型ALL或index,這就會發(fā)生,或者是查詢有問題不同連接類型的解釋(按照效率高低的順序排序)

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI