索引

1.1 索引概述

MySQL官方對索引的定義為:索引(index)是幫助MySQL高效獲取數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)(有序)痛悯。在數(shù)據(jù)之外肯骇,數(shù)據(jù)庫系統(tǒng)還維護(hù)者滿足特定查找算法的數(shù)據(jù)結(jié)構(gòu)后添,這些數(shù)據(jù)結(jié)構(gòu)以某種方式引用(指向)數(shù)據(jù)愤钾, 這樣就可以在這些數(shù)據(jù)結(jié)構(gòu)上實(shí)現(xiàn)高級查找算法,這種數(shù)據(jù)結(jié)構(gòu)就是索引坎藐。如下面的==示意圖==所示 :

左邊是數(shù)據(jù)表兢榨,一共有兩列七條記錄,最左邊的是數(shù)據(jù)記錄的物理地址(注意邏輯上相鄰的記錄在磁盤上也并不是一定物理相鄰的)。為了加快Col2的查找吵聪,可以維護(hù)一個(gè)右邊所示的二叉查找樹,每個(gè)節(jié)點(diǎn)分別包含索引鍵值和一個(gè)指向?qū)?yīng)數(shù)據(jù)記錄物理地址的指針兼雄,這樣就可以運(yùn)用二叉查找快速獲取到相應(yīng)數(shù)據(jù)吟逝。

一般來說索引本身也很大,不可能全部存儲在內(nèi)存中赦肋,因此索引往往以索引文件的形式存儲在磁盤上块攒。索引是數(shù)據(jù)庫中用來提高性能的最常用的工具。

2.1索引優(yōu)勢劣勢

優(yōu)勢

1) 類似于書籍的目錄索引佃乘,提高數(shù)據(jù)檢索的效率囱井,降低數(shù)據(jù)庫的IO成本。

2) 通過索引列對數(shù)據(jù)進(jìn)行排序趣避,降低數(shù)據(jù)排序的成本庞呕,降低CPU的消耗。

劣勢

1) 實(shí)際上索引也是一張表程帕,該表中保存了主鍵與索引字段住练,并指向?qū)嶓w類的記錄,所以索引列也是要占用空間的愁拭。

2) 雖然索引大大提高了查詢效率讲逛,同時(shí)卻也降低更新表的速度,如對表進(jìn)行INSERT岭埠、UPDATE盏混、DELETE。因?yàn)楦卤頃r(shí)惜论,MySQL 不僅要保存數(shù)據(jù)许赃,還要保存一下索引文件每次更新添加了索引列的字段,都會調(diào)整因?yàn)楦滤鶐淼逆I值變化后的索引信息来涨。

2.3 索引結(jié)構(gòu)

索引是在MySQL的存儲引擎層中實(shí)現(xiàn)的图焰,而不是在服務(wù)器層實(shí)現(xiàn)的。所以每種存儲引擎的索引都不一定完全相同蹦掐,也不是所有的存儲引擎都支持所有的索引類型的技羔。MySQL目前提供了以下4種索引:

  • BTREE 索引 : 最常見的索引類型,大部分索引都支持 B 樹索引卧抗。
  • HASH 索引:只有Memory引擎支持 藤滥, 使用場景簡單 。
  • R-tree 索引(空間索引):空間索引是MyISAM引擎的一個(gè)特殊索引類型社裆,主要用于地理空間數(shù)據(jù)類型拙绊,通常使用較少,不做特別介紹。
  • Full-text (全文索引) :全文索引也是MyISAM的一個(gè)特殊索引類型标沪,主要用于全文索引榄攀,InnoDB從Mysql5.6版本開始支持全文索引。

MyISAM金句、InnoDB檩赢、Memory三種存儲引擎對各種索引類型的支持


我們平常所說的索引,如果沒有特別指明违寞,都是指B+樹(多路搜索樹贞瞒,并不一定是二叉的)結(jié)構(gòu)組織的索引。其中聚集索引趁曼、復(fù)合索引军浆、前綴索引、唯一索引默認(rèn)都是使用 B+tree 索引挡闰,統(tǒng)稱為 索引乒融。

2.3.1 BTREE 結(jié)構(gòu)


BTREE樹 和 二叉樹 相比, 查詢數(shù)據(jù)的效率更高尿这, 因?yàn)閷τ谙嗤臄?shù)據(jù)量來說簇抵,BTREE的層級結(jié)構(gòu)比二叉樹小,因此搜索速度快射众。

2.3.2 B+TREE 結(jié)構(gòu)

B+Tree為BTree的變種碟摆,B+Tree與BTree的區(qū)別為:

1). n叉B+Tree最多含有n個(gè)key,而BTree最多含有n-1個(gè)key叨橱。

2). B+Tree的葉子節(jié)點(diǎn)保存所有的key信息典蜕,依key大小順序排列。

3). 所有的非葉子節(jié)點(diǎn)都可以看作是key的索引部分罗洗。



由于B+Tree只有葉子節(jié)點(diǎn)保存key信息愉舔,查詢?nèi)魏蝛ey都要從root走到葉子。所以B+Tree的查詢效率更加穩(wěn)定伙菜。

2.3.3 MySQL中的B+Tree

MySql索引數(shù)據(jù)結(jié)構(gòu)對經(jīng)典的B+Tree進(jìn)行了優(yōu)化轩缤。在原B+Tree的基礎(chǔ)上,增加一個(gè)指向相鄰葉子節(jié)點(diǎn)的鏈表指針贩绕,就形成了帶有順序指針的B+Tree火的,提高區(qū)間訪問的性能。
MySQL中的 B+Tree 索引結(jié)構(gòu)示意圖:


2.4 索引分類

1) 單值索引 :即一個(gè)索引只包含單個(gè)列淑倾,一個(gè)表可以有多個(gè)單列索引

2) 唯一索引 :索引列的值必須唯一馏鹤,但允許有空值

3) 復(fù)合索引 :即一個(gè)索引包含多個(gè)列

2.5 索引語法

索引在創(chuàng)建表的時(shí)候,可以同時(shí)創(chuàng)建娇哆, 也可以隨時(shí)增加新的索引湃累。

準(zhǔn)備環(huán)境:

create database demo_01 default charset=utf8mb4;

use demo_01;

CREATE TABLE `city` (
  `city_id` int(11) NOT NULL AUTO_INCREMENT,
  `city_name` varchar(50) NOT NULL,
  `country_id` int(11) NOT NULL,
  PRIMARY KEY (`city_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `country` (
  `country_id` int(11) NOT NULL AUTO_INCREMENT,
  `country_name` varchar(100) NOT NULL,
  PRIMARY KEY (`country_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


insert into `city` (`city_id`, `city_name`, `country_id`) values(1,'西安',1);
insert into `city` (`city_id`, `city_name`, `country_id`) values(2,'NewYork',2);
insert into `city` (`city_id`, `city_name`, `country_id`) values(3,'北京',1);
insert into `city` (`city_id`, `city_name`, `country_id`) values(4,'上海',1);

insert into `country` (`country_id`, `country_name`) values(1,'China');
insert into `country` (`country_id`, `country_name`) values(2,'America');
insert into `country` (`country_id`, `country_name`) values(3,'Japan');
insert into `country` (`country_id`, `country_name`) values(4,'UK');

2.5.1 創(chuàng)建索引

語法 :

CREATE  [UNIQUE|FULLTEXT|SPATIAL]  INDEX index_name 
[USING  index_type]
ON tbl_name(index_col_name,...)


index_col_name : column_name[(length)][ASC | DESC]

示例 : 為city表中的city_name字段創(chuàng)建索引 勃救;


2.5.2 查看索引

語法:

show index  from  table_name;

示例:查看city表中的索引信息


2.5.3 刪除索引

語法 :

DROP  INDEX  index_name  ON  tbl_name;

示例 : 想要?jiǎng)h除city表上的索引idx_city_name,可以操作如下:


2.5.4 ALTER命令

1). alter table tb_name add primary key(column_list);

該語句添加一個(gè)主鍵治力,這意味著索引值必須是唯一的蒙秒,且不能為NULL

2). alter table tb_name add unique index_name(column_list);

這條語句創(chuàng)建索引的值必須是唯一的(除了NULL外,NULL可能會出現(xiàn)多次)

3). alter table tb_name add index index_name(column_list);

添加普通索引宵统, 索引值可以出現(xiàn)多次税肪。

4). alter table tb_name add fulltext index_name(column_list);

該語句指定了索引為FULLTEXT, 用于全文索引

2.6 索引設(shè)計(jì)原則

索引的設(shè)計(jì)可以遵循一些已有的原則榜田,創(chuàng)建索引的時(shí)候請盡量考慮符合這些原則,便于提升索引的使用效率锻梳,更高效的使用索引箭券。
  • 對查詢頻次較高,且數(shù)據(jù)量比較大的表建立索引疑枯。

  • 索引字段的選擇辩块,最佳候選列應(yīng)當(dāng)從where子句的條件中提取,如果where子句中的組合比較多荆永,那么應(yīng)當(dāng)挑選最常用废亭、過濾效果最好的列的組合。

  • 使用唯一索引具钥,區(qū)分度越高豆村,使用索引的效率越高。

  • 索引可以有效的提升查詢數(shù)據(jù)的效率骂删,但索引數(shù)量不是多多益善掌动,索引越多,維護(hù)索引的代價(jià)自然也就水漲船高宁玫。對于插入粗恢、更新、刪除等DML操作比較頻繁的表來說欧瘪,索引過多眷射,會引入相當(dāng)高的維護(hù)代價(jià),降低DML操作的效率佛掖,增加相應(yīng)操作的時(shí)間消耗妖碉。另外索引過多的話,MySQL也會犯選擇困難病苦囱,雖然最終仍然會找到一個(gè)可用的索引嗅绸,但無疑提高了選擇的代價(jià)。

  • 使用短索引撕彤,索引創(chuàng)建之后也是使用硬盤來存儲的鱼鸠,因此提升索引訪問的I/O效率猛拴,也可以提升總體的訪問效率。假如構(gòu)成索引的字段總長度比較短蚀狰,那么在給定大小的存儲塊內(nèi)可以存儲更多的索引值愉昆,相應(yīng)的可以有效的提升MySQL訪問索引的I/O效率。

  • 利用最左前綴麻蹋,N個(gè)列組合而成的組合索引跛溉,那么相當(dāng)于是創(chuàng)建了N個(gè)索引,如果查詢時(shí)where子句中使用了組成該索引的前幾個(gè)字段扮授,那么這條查詢SQL可以利用組合索引來提升查詢效率芳室。

創(chuàng)建復(fù)合索引:

    CREATE INDEX idx_name_email_status ON tb_seller(NAME,email,STATUS);

就相當(dāng)于
    對name 創(chuàng)建索引 ;
    對name , email 創(chuàng)建了索引 ;
    對name , email, status 創(chuàng)建了索引 ;

4.2 索引的使用

4.2.1 準(zhǔn)備環(huán)境

create table `tb_seller` (
    `sellerid` varchar (100),
    `name` varchar (100),
    `nickname` varchar (50),
    `password` varchar (60),
    `status` varchar (1),
    `address` varchar (100),
    `createtime` datetime,
    primary key(`sellerid`)
)engine=innodb default charset=utf8mb4; 

insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('alibaba','阿里巴巴','阿里小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('baidu','百度科技有限公司','百度小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('huawei','華為科技有限公司','華為小店','e10adc3949ba59abbe56e057f20f883e','0','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('itcast','傳智播客教育科技有限公司','傳智播客','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('itheima','黑馬程序員','黑馬程序員','e10adc3949ba59abbe56e057f20f883e','0','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('luoji','羅技科技有限公司','羅技小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('oppo','OPPO科技有限公司','OPPO官方旗艦店','e10adc3949ba59abbe56e057f20f883e','0','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('ourpalm','掌趣科技股份有限公司','掌趣小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('qiandu','千度科技','千度小店','e10adc3949ba59abbe56e057f20f883e','2','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('sina','新浪科技有限公司','新浪官方旗艦店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('xiaomi','小米科技','小米官方旗艦店','e10adc3949ba59abbe56e057f20f883e','1','西安市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('yijia','宜家家居','宜家家居旗艦店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');


create index idx_seller_name_sta_addr on tb_seller(name,status,address);

4.2.2 避免索引失效

1). 全值匹配 ,對索引中所有列都指定具體值刹勃。

explain select * from tb_seller where name='小米科技' and status='1' and address='北京市'\G;


2). 最左前綴法則

如果索引了多列堪侯,要遵守最左前綴法則。指的是查詢從索引的最左前列開始荔仁,并且不跳過索引中的列伍宦。
匹配最左前綴法則,走索引:


違法最左前綴法則 乏梁, 索引失效:

如果符合最左法則次洼,但是出現(xiàn)跳躍某一列,只有最左列索引生效:

3). 范圍查詢右邊的列遇骑,不能使用索引 卖毁。

根據(jù)前面的兩個(gè)字段name , status 查詢是走索引的质蕉, 但是最后一個(gè)條件address 沒有用到索引势篡。
4). 不要在索引列上進(jìn)行運(yùn)算操作, 索引將失效模暗。

5). 字符串不加單引號禁悠,造成索引失效。

由于兑宇,在查詢是碍侦,沒有對字符串加單引號,MySQL的查詢優(yōu)化器隶糕,會自動的進(jìn)行類型轉(zhuǎn)換瓷产,造成索引失效。
6). 盡量使用覆蓋索引枚驻,避免select*

盡量使用覆蓋索引(只訪問索引的查詢(索引列完全包含查詢列))濒旦,減少select * 。


如果查詢列再登,超出索引列尔邓,也會降低性能晾剖。

7). 用or分割開的條件, 如果or前的條件中的列有索引梯嗽,而后面的列中沒有索引齿尽,那么涉及的索引都不會被用到。

示例灯节,name字段是索引列 循头, 而createtime不是索引列,中間是or進(jìn)行連接是不走索引的 :

explain select * from tb_seller where name='黑馬程序員' or createtime = '2088-01-01 12:00:00'\G; 


8). 以%開頭的Like模糊查詢炎疆,索引失效卡骂。

如果僅僅是尾部模糊匹配,索引不會失效形入。如果是頭部模糊匹配偿警,索引失效。



解決方案 :

通過覆蓋索引來解決


9). 如果MySQL評估使用索引比全表更慢唯笙,則不使用索引。

10). is NULL 盒使, is NOT NULL 有時(shí)索引失效崩掘。

11). in 走索引, not in 索引失效少办。

12). 單列索引和復(fù)合索引苞慢。

盡量使用復(fù)合索引,而少使用單列索引 英妓。

創(chuàng)建復(fù)合索引

create index idx_name_sta_address on tb_seller(name, status, address);

就相當(dāng)于創(chuàng)建了三個(gè)索引 : 
    name
    name + status
    name + status + address

創(chuàng)建單列索引

create index idx_seller_name on tb_seller(name);
create index idx_seller_status on tb_seller(status);
create index idx_seller_address on tb_seller(address);

數(shù)據(jù)庫會選擇一個(gè)最優(yōu)的索引(辨識度最高索引)來使用挽放,并不會使用全部索引 。

4.3 查看索引使用情況

show status like 'Handler_read%';   

show global status like 'Handler_read%';    
Handler_read_first:索引中第一條被讀的次數(shù)蔓纠。如果較高辑畦,表示服務(wù)器正執(zhí)行大量全索引掃描(這個(gè)值越低越好)。

Handler_read_key:如果索引正在工作腿倚,這個(gè)值代表一個(gè)行被索引值讀的次數(shù)纯出,如果值越低,表示索引得到的性能改善不高敷燎,因?yàn)樗饕唤?jīng)常使用(這個(gè)值越高越好)暂筝。

Handler_read_next :按照鍵順序讀下一行的請求數(shù)。如果你用范圍約束或如果執(zhí)行索引掃描來查詢索引列硬贯,該值增加焕襟。

Handler_read_prev:按照鍵順序讀前一行的請求數(shù)。該讀方法主要用于優(yōu)化ORDER BY ... DESC饭豹。

Handler_read_rnd :根據(jù)固定位置讀一行的請求數(shù)鸵赖。如果你正執(zhí)行大量查詢并需要對結(jié)果進(jìn)行排序該值較高务漩。你可能使用了大量需要MySQL掃描整個(gè)表的查詢或你的連接沒有正確使用鍵。這個(gè)值較高卫漫,意味著運(yùn)行效率低菲饼,應(yīng)該建立索引來補(bǔ)救。

Handler_read_rnd_next:在數(shù)據(jù)文件中讀下一行的請求數(shù)列赎。如果你正進(jìn)行大量的表掃描宏悦,該值較高。通常說明你的表索引不正確或?qū)懭氲牟樵儧]有利用索引包吝。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末饼煞,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子诗越,更是在濱河造成了極大的恐慌砖瞧,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嚷狞,死亡現(xiàn)場離奇詭異块促,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)床未,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門竭翠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人薇搁,你說我怎么就攤上這事斋扰。” “怎么了啃洋?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵传货,是天一觀的道長。 經(jīng)常有香客問我宏娄,道長问裕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任孵坚,我火速辦了婚禮僻澎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘十饥。我一直安慰自己窟勃,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布逗堵。 她就那樣靜靜地躺著秉氧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蜒秤。 梳的紋絲不亂的頭發(fā)上汁咏,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天亚斋,我揣著相機(jī)與錄音,去河邊找鬼攘滩。 笑死帅刊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的漂问。 我是一名探鬼主播赖瞒,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蚤假!你這毒婦竟也來了栏饮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤磷仰,失蹤者是張志新(化名)和其女友劉穎袍嬉,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體灶平,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡伺通,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了逢享。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泵殴。...
    茶點(diǎn)故事閱讀 38,599評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖拼苍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情调缨,我是刑警寧澤疮鲫,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站弦叶,受9級特大地震影響俊犯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜伤哺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一燕侠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧立莉,春花似錦绢彤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至刹淌,卻和暖如春饶氏,著一層夾襖步出監(jiān)牢的瞬間讥耗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工疹启, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留古程,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓喊崖,卻偏偏與公主長得像挣磨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子贷祈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容